有没有一种方法可以使用Go语言生成UUID?

huangapple go评论89阅读模式
英文:

Is there a method to generate a UUID with Go language?

问题

我有一段代码看起来像这样:

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

u[8] = (u[8] | 0x80) & 0xBF // 这段代码是做什么的?
u[6] = (u[6] | 0x40) & 0x4F // 这段代码是做什么的?

return hex.EncodeToString(u)

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

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

英文:

I have code that looks like this:

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)

It returns a string with a length of 32, but I don't think it is a valid UUID. If it is a real UUID, why is it a UUID, and what is the purpose of the code that modifies the value of u[8] and u[6]?

Is there a better way of generating UUIDs?

答案1

得分: 197

这里有一个由Google官方提供的实现: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

英文:

There is an official implementation by Google: https://github.com/google/uuid

Generating a version 4 UUID works like this:

package main

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

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

Try it here: https://play.golang.org/p/6YPi1djUMj9

答案2

得分: 114

你可以使用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)。

英文:

You can generate UUIDs using the go-uuid library. This can be installed with:

go get github.com/nu7hatch/gouuid

You can generate random (version 4) UUIDs with:

import "github.com/nu7hatch/gouuid"

...

u, err := uuid.NewV4()

The returned UUID type is a 16 byte array, so you can retrieve the binary value easily. It also provides the standard hex string representation via its String() method.

The code you have also looks like it will also generate a valid version 4 UUID: the bitwise manipulation you perform at the end set the version and variant fields of the UUID to correctly identify it as version 4. This is done to distinguish random UUIDs from ones generated via other algorithms (e.g. version 1 UUIDs based on your MAC address and time).

答案3

得分: 78

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和v5 UUID。还有几个新的方法可用于打印和格式化,以及基于现有数据创建UUID的新通用方法。

英文:

The go-uuid library is NOT RFC4122 compliant. The variant bits are not set correctly. There have been several attempts by community members to have this fixed but pull requests for the fix are not being accepted.

You can generate UUIDs using the Go uuid library I rewrote based on the go-uuid library. There are several fixes and improvements. This can be installed with:

go get github.com/twinj/uuid

You can generate random (version 4) UUIDs with:

import "github.com/twinj/uuid"

u := uuid.NewV4()

The returned UUID type is an interface and the underlying type is an array.

The library also generates v1 UUIDs and correctly generates v3 and 5 UUIDs. There are several new methods to help with printing and formatting and also new general methods to create UUIDs based off of existing data.

答案4

得分: 61

"crypto/rand"是一个用于生成随机字节的跨平台包

package main

import (
	"crypto/rand"
	"fmt"
)

// 注意 - 不符合RFC4122标准
func pseudo_uuid() (uuid string) {

	b := make([]byte, 16)
	_, err := rand.Read(b)
	if err != nil {
		fmt.Println("错误: ", 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
}
英文:

"crypto/rand" is cross platform pkg for random bytes generattion

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
}

答案5

得分: 34

u[8] = (u[8] | 0x80) & 0xBF // 这是什么目的?
u[6] = (u[6] | 0x40) & 0x4F // 这是什么目的?

这些代码行将字节6和8的值限制在特定范围内。rand.Read返回的是在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
英文:
u[8] = (u[8] | 0x80) & 0xBF // what's the purpose ?
u[6] = (u[6] | 0x40) & 0x4F // what's the purpose ?

These lines clamp the values of byte 6 and 8 to a specific range. rand.Read returns random bytes in the range 0-255, which are not all valid values for a UUID. As far as I can tell, this should be done for all the values in the slice though.

If you are on linux, you can alternatively call /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)
}

Which yields:

$ go run uuid.go 
dc9076e9-2fda-4019-bd2c-900a8284b9c4

答案6

得分: 32

gofrs/uuidsatori/go.uuid 的替代品,它是 Go 语言中最受欢迎的 UUID 包,支持 UUID 版本 1-5,并符合 RFC 4122 和 DCE 1.1 标准。

import "github.com/gofrs/uuid"

// 创建一个版本 4 的 UUID,如果出错则会引发 panic
u := uuid.Must(uuid.NewV4())
英文:

gofrs/uuid is the replacement for satori/go.uuid, which is the most starred UUID package for Go. It supports UUID versions 1-5 and is RFC 4122 and DCE 1.1 compliant.

import "github.com/gofrs/uuid"

// Create a Version 4 UUID, panicking on error
u := uuid.Must(uuid.NewV4())

答案7

得分: 12

从Russ Cox的帖子中:

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

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)

这里它可以编译和执行,只是在playground中/dev/urandom返回全零。在本地应该可以正常工作。

在同一线程中还有一些其他的方法/参考/包。

英文:

From Russ Cox's post:

> There's no official library. Ignoring error checking,
> this seems like it would work fine:

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:])

Note: In the original, pre Go 1 version the first line was:

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

Here it compiles and executes, only /dev/urandom returns all zeros in the playground. Should work fine locally.

In the same thread there are some other methods/references/packages found.

答案8

得分: 9

使用谷歌的包生成随机UUID:

package main

import (
    "fmt"

    "github.com/google/uuid"
)

func main() {
    out := uuid.Must(uuid.NewRandom()).String()
    fmt.Println(out)
}

输出:

a1c11a53-c4be-488f-89b6-f83bf2d48dab
英文:

Random UUID using package from google:

package main

import (
	"fmt"

	"github.com/google/uuid"
)

func main() {
	out := uuid.Must(uuid.NewRandom()).String()
	fmt.Println(out)
}

Output:

a1c11a53-c4be-488f-89b6-f83bf2d48dab

答案9

得分: 8

作为uuid规范的一部分,如果你从随机生成一个uuid,它必须包含一个"4"作为第13个字符,并且在第17个字符位置上包含一个"8"、"9"、"a"或"b"(来源)。

// 这确保第13个字符是"4"
u[6] = (u[6] | 0x40) & 0x4F
// 这确保第17个字符是"8"、"9"、"a"或"b"
u[8] = (u[8] | 0x80) & 0xBF

英文:

As part of the uuid spec, if you generate a uuid from random it must contain a "4" as the 13th character and a "8", "9", "a", or "b" in the 17th (source).

// 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 

答案10

得分: 7

在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
英文:

On Linux, you can read from /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))
}

No external dependencies!

$ go run uuid.go 
3ee995e3-0c96-4e30-ac1e-f7f04fd03e44

答案11

得分: 4

The gorand package has a UUID method that returns a Version 4 (randomly generated) UUID in its canonical string representation ("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx") and it's RFC 4122 compliant.

It also uses the crypto/rand package to ensure the most cryptographically secure generation of UUIDs across all platforms supported by Go.

import "github.com/leonelquinteros/gorand"

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

    println(uuid)
} 
英文:

The gorand package has a UUID method that returns a Version 4 (randomly generated) UUID in its canonical string representation ("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx") and it's RFC 4122 compliant.

It also uses the crypto/rand package to ensure the most cryptographically secure generation of UUIDs across all platforms supported by Go.

import "github.com/leonelquinteros/gorand"

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

    println(uuid)
} 

答案12

得分: 3

所以你问:<br>
Q1. u[8] = (u[8] | 0x80) & 0xBF // 这是什么意思?<br>
答: 这部分定义了变体。你可以从https://datatracker.ietf.org/doc/html/rfc4122#section-4.1.1了解更多信息。

Q2. u[6] = (u[6] | 0x40) & 0x4F // 这是什么意思?<br>
答: 我们使用最高的4位来表示版本号,所以在这种情况下版本号为4,所以我们想要将其设置为"0100"。版本4是最常用的UUID版本,它基于随机位生成。它使用128位,其中4位固定用于表示版本号,2位固定用于表示变体。因此,我们还剩下122位可以随机生成。<br>

你可以通过导入Google的包来生成UUID v4:<br>
https://github.com/google/uuid

package main

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

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

另外,你也可以尝试我创建的包。它非常轻量且易于理解。https://github.com/bitactro/UUIDv4 <br>

package main

import (
    "fmt"
    "github.com/bitactro/UUIDv4"
)

func main() {
    
    fmt.Println(uuidv4.GenerateUUID4())
}
英文:

So you asked:<br>
Q1. u[8] = (u[8] | 0x80) & 0xBF // what does this do?<br>
Ans: This section defines variant. You can learn more about it from https://datatracker.ietf.org/doc/html/rfc4122#section-4.1.1

Q2. u[6] = (u[6] | 0x40) & 0x4F // what does this do?<br>
Ans: We show version number with the most 4 significant bits so in this case version 4 so we want to set it with &quot;0100&quot;. Version 4 is most widely used UUID and its based on random bits generation. It uses 128 bits, Out of which 4 bits are fixed to tell version number and 2 bits are fixed to tell variant. So we have 122 bits left which can be randomly generated.<br>

You can generate UUID v4 by importing package from Google:<br>
https://github.com/google/uuid

package main

import (
    &quot;fmt&quot;
    &quot;github.com/google/uuid&quot;
)

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

Also, you can try package I created. It's very light weight and easy to understand. https://github.com/bitactro/UUIDv4 <br>

package main

import (
    &quot;fmt&quot;
    &quot;github.com/bitactro/UUIDv4&quot;
)

func main() {
    
    fmt.Println(uuidv4.GenerateUUID4())
}

答案13

得分: 1

// +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
}

英文:

For Windows, I did recently this:

// +build windows

package main

import (
    &quot;syscall&quot;
    &quot;unsafe&quot;
)

var (
    modrpcrt4 = syscall.NewLazyDLL(&quot;rpcrt4.dll&quot;)
    procUuidCreate = modrpcrt4.NewProc(&quot;UuidCreate&quot;)
)

const (
    RPC_S_OK = 0
)

func NewUuid() ([]byte, error) {
    var uuid [16]byte
    rc, _, e := syscall.Syscall(procUuidCreate.Addr(), 1,
             uintptr(unsafe.Pointer(&amp;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
}

答案14

得分: 1

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

https://github.com/pborman/uuid

英文:

This library is our standard for uuid generation and parsing:

https://github.com/pborman/uuid

答案15

得分: 1

The https://github.com/google/uuid module based on RFC 4122 and UUID V4 is currently supported. If you want to use the latest UUID version like UUID v7,
This module https://github.com/uuid6/uuid6go-proto could be used.


UUID version 7: An entirely new time-based UUID bit layout sourced from the widely implemented and well known Unix Epoch timestamp source.

unix_ts_ms|ver|rand_a|var|rand_b 

Since the UUID V4 contains random and it is not used for sorting. However, there is a timestamp part on UUID V7, it would be more friendly for sorting.


Sample

	var gen uuid.UUIDv7Generator

	uuid := gen.Next()
	fmt.Println(uuid.ToString())
	fmt.Println(uuid.Time())
	fmt.Println(uuid.Timestamp())

Output

0632933765-357c-31b6-ed56-0daba726b1
2022-09-20 11:28:54 +0800 CST
1663644534
英文:

The https://github.com/google/uuid module based on RFC 4122 and UUID V4 is currently supported. If you want to use the latest UUID version like UUID v7,
This module https://github.com/uuid6/uuid6go-proto could be used.


UUID version 7: An entirely new time-based UUID bit layout sourced from the widely implemented and well known Unix Epoch timestamp source.

unix_ts_ms|ver|rand_a|var|rand_b 

Since the UUID V4 contains random and it is not used for sorting. However, there is a timestamp part on UUID V7, it would be more friendly for sorting.


Sample

	var gen uuid.UUIDv7Generator

	uuid := gen.Next()
	fmt.Println(uuid.ToString())
	fmt.Println(uuid.Time())
	fmt.Println(uuid.Timestamp())

Output

0632933765-357c-31b6-ed56-0daba726b1
2022-09-20 11:28:54 +0800 CST
1663644534

huangapple
  • 本文由 发表于 2013年2月28日 15:58:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/15130321.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定