146

我的代码如下所示:

u := make([]byte, 16)
_, err := rand.Read(u)
if err != nil {
    return
}

u[8] = (u[8] | 0x80) & 0xBF // what does this do?
u[6] = (u[6] | 0x40) & 0x4F // what does this do?

return hex.EncodeToString(u)

它返回一个长度为 32 的字符串,但我认为它不是有效的 UUID。如果是真正的 UUID,为什么是 UUID,修改u[8]and的值的代码的目的是什么u[6]

有没有更好的方法来生成 UUID?

4

12 回答 12

110

谷歌有一个官方实现:https ://github.com/google/uuid

生成版本 4 UUID 的工作方式如下:

package main

import (
    "fmt"
    "github.com/google/uuid"
)

func main() {
    id := uuid.New()
    fmt.Println(id.String())
}

在这里试试:https: //play.golang.org/p/6YPi1djUMj9

于 2017-11-22T11:49:29.770 回答
108

您可以使用go-uuid库生成 UUID。这可以安装:

go get github.com/nu7hatch/gouuid

您可以使用以下命令生成随机(版本 4)UUID:

import "github.com/nu7hatch/gouuid"

...

u, err := uuid.NewV4()

返回的UUID类型是一个 16 字节的数组,因此您可以轻松检索二进制值。它还通过其String()方法提供标准的十六进制字符串表示。

您的代码看起来也将生成有效的版本 4 UUID:您在最后执行的按位操作设置 UUID 的版本和变体字段以正确地将其识别为版本 4。这样做是为了将随机 UUID 与通过其他算法生成的 UUID 区分开来(例如,基于您的 MAC 地址和时间的版本 1 UUID)。

于 2013-02-28T11:33:48.053 回答
73

go-uuid库不符合 RFC4122。变量位设置不正确。社区成员多次尝试修复此问题,但未接受修复请求。

您可以使用我基于该go-uuid库重写的 Go uuid 库生成 UUID。有几个修复和改进。这可以安装:

go get github.com/twinj/uuid

您可以使用以下命令生成随机(版本 4)UUID:

import "github.com/twinj/uuid"

u := uuid.NewV4()

返回的 UUID 类型是一个接口,底层类型是一个数组。

该库还生成 v1 UUID 并正确生成 v3 和 5 UUID。有几种新方法可以帮助打印和格式化,还有新的通用方法可以根据现有数据创建 UUID。

于 2014-02-17T07:03:40.113 回答
60

“crypto/rand”是用于随机字节生成的跨平台 pkg

package main

import (
    "crypto/rand"
    "fmt"
)

// Note - NOT RFC4122 compliant
func pseudo_uuid() (uuid string) {

    b := make([]byte, 16)
    _, err := rand.Read(b)
    if err != nil {
        fmt.Println("Error: ", err)
        return
    }

    uuid = fmt.Sprintf("%X-%X-%X-%X-%X", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])

    return
}
于 2014-09-09T03:12:46.023 回答
32
u[8] = (u[8] | 0x80) & 0xBF // what's the purpose ?
u[6] = (u[6] | 0x40) & 0x4F // what's the purpose ?

这些行将字节 6 和 8 的值限制在特定范围内。rand.Read返回 range 中的随机字节0-255,这不是 UUID 的所有有效值。据我所知,这应该对切片中的所有值进行。

如果你在 linux 上,你也可以调用/usr/bin/uuidgen.

package main

import (
    "fmt"
    "log"
    "os/exec"
)

func main() {
    out, err := exec.Command("uuidgen").Output()
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%s", out)
}

产生:

$ go run uuid.go 
dc9076e9-2fda-4019-bd2c-900a8284b9c4
于 2013-02-28T08:36:55.020 回答
28

gofrs/uuid是 satori/go.uuid 的替代品它是Go 的星号最多的 UUID 包。它支持 UUID 版本 1-5,并且符合 RFC 4122 和 DCE 1.1。

import "github.com/gofrs/uuid"

// Create a Version 4 UUID, panicking on error
u := uuid.Must(uuid.NewV4())
于 2016-04-25T19:14:13.240 回答
11

来自拉斯考克斯的帖子

没有官方图书馆。忽略错误检查,这似乎可以正常工作:

f, _ := os.Open("/dev/urandom")
b := make([]byte, 16)
f.Read(b)
f.Close()
uuid := fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])

注意:在 Go 1 之前的原始版本中,第一行是:

f, _ := os.Open("/dev/urandom", os.O_RDONLY, 0)

它在这里编译并执行,只/dev/urandom在操场上返回全零。在本地应该可以正常工作。

在同一个线程中,还发现了一些其他方法/参考/包。

于 2013-02-28T08:38:32.973 回答
8

作为 uuid 规范的一部分,如果您从随机生成一个 uuid,它必须在第 13 个字符包含“4”,在第 17 个字符()中包含“8”、“9”、“a”或“b”。

// this makes sure that the 13th character is "4"
u[6] = (u[6] | 0x40) & 0x4F
// this makes sure that the 17th is "8", "9", "a", or "b"
u[8] = (u[8] | 0x80) & 0xBF 
于 2015-01-06T05:57:13.230 回答
6

在 Linux 上,您可以阅读/proc/sys/kernel/random/uuid

package main

import "io/ioutil"
import "fmt"

func main() {
    u, _ := ioutil.ReadFile("/proc/sys/kernel/random/uuid")
    fmt.Println(string(u))
}

没有外部依赖!

$ go run uuid.go 
3ee995e3-0c96-4e30-ac1e-f7f04fd03e44
于 2017-11-08T03:59:35.743 回答
4

gorand包有一个 UUID 方法,以规范的字符串表示形式(“xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx”)返回版本 4(随机生成的)UUID,并且它符合 RFC 4122。

它还使用 crypto/rand 包来确保在 Go 支持的所有平台上最安全地生成 UUID。

import "github.com/leonelquinteros/gorand"

func main() {
    uuid, err := gorand.UUID()
    if err != nil {
        panic(err.Error())
    }

    println(uuid)
} 
于 2016-06-15T00:00:39.450 回答
1

对于 Windows,我最近这样做了:

// +build windows

package main

import (
    "syscall"
    "unsafe"
)

var (
    modrpcrt4 = syscall.NewLazyDLL("rpcrt4.dll")
    procUuidCreate = modrpcrt4.NewProc("UuidCreate")
)

const (
    RPC_S_OK = 0
)

func NewUuid() ([]byte, error) {
    var uuid [16]byte
    rc, _, e := syscall.Syscall(procUuidCreate.Addr(), 1,
             uintptr(unsafe.Pointer(&uuid[0])), 0, 0)
    if int(rc) != RPC_S_OK {
        if e != 0 {
            return nil, error(e)
        } else {
            return nil, syscall.EINVAL
        }
    }
    return uuid[:], nil
}
于 2013-02-28T09:22:57.227 回答
1

这个库是我们 uuid 生成和解析的标准:

https://github.com/pborman/uuid

于 2015-08-14T18:10:39.003 回答