uuid是Universally Unique Identifier的缩写,即通用唯一识别码。
uuid的目的是让分布式系统中的所有元素,都能有唯一的辨识资讯,而不需要透过中央控制端来做辨识资讯的指定。如此一来,每个人都可以建立不与其它人冲突的 uuid。
uuid是谷歌开发的生成16字节UUID的模块,实现了RFC4122;对UUID的v1,v2,v3,v4,v5等各个版本都有实现。一般来说,如果只是要生成唯一序列号的话,通常用v4版本,New()和NewRandom()
都可以生成v4, New
是对NewRandom
的封装把error处理成panics了,但是理论上几乎是不会有发生panics的可能的。
func New() UUID
func NewRandom() (UUID, error)
package main
import (
"fmt"
"github.com/google/uuid"
)
func main() {
for i:=0; i<2; i++ {
id := uuid.New()
fmt.Printf("%T,%v\n",id,id)
fmt.Printf("%v,%v,%v\n",id.String(),id.Version(),id.Version().String())
}
fmt.Println("-------------------------------")
for i:=0; i<2; i++ {
id2,err := uuid.NewRandom()
if err != nil {
fmt.Println(err)
}
fmt.Printf("%T,%v\n",id2,id2)
fmt.Printf("%v,%v,%v\n",id2.String(),id2.Version(),id2.Version().String())
}
}
官方文档上说New方法可能会有panics,但从源码来看基本上没有报错的可能。会不会报错取决于"crypto/rand"的Reader能不能读满到16个随机字节,而Reader又是从Linux操作系统的getrandom(2) 读取若没有则从 /dev/urandom 读取,getrandom(2)的文档说256个字节以内都不会被信号中断,而/dev/urandom的文档也没有说会有报错的可能。所以理论上是没有报错的可能的。
uuid是谷歌开发的生成16字节UUID的模块,实现了RFC4122;对UUID的v1,v2,v3,v4,v5等各个版本都有实现。使用方法示例如下:
package main
import (
"fmt"
"github.com/google/uuid"
)
// v1,v4都是每次生成一个唯一的ID.
// v1同一时刻的输出非常相似,v1末尾nodeID部分用的都是mac地址,前面time的mid,high以及clock序列都是一样的,只有time-low部分不同。
func testv1() {
id,err := uuid.NewUUID()
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("testv1: %v,%v\n",id,id.Version().String())
}
// v4加入了随机数,对各个部分都进行了随机处理,同一时刻的输出差别很大。
func testv4() {
id := uuid.New()
fmt.Printf("testv4: %v,%v\n",id,id.Version().String())
}
// v2 NewDCEGroup()根据os.Getgid取到的用户组ID来生成uuid,同一时刻的输出是相同的。
func testv2G() {
id,err := uuid.NewDCEGroup()
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("testv2G: %v,%v\n",id,id.Version().String())
}
// v2 NewDCEPerson()根据os.Getuid取到的用户ID来生成uuid,同一时刻的输出也是相同的。
func testv2P() {
id,err := uuid.NewDCEPerson()
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("testv2P: %v,%v\n",id,id.Version().String())
}
// v3 NewMD5(space UUID, data []byte)是根据参数传入的UUID结构体和[]byte再重新转换一次。只要传入参数相同则任意时刻的输出也相同。
func testv3() {
id0,err := uuid.NewDCEPerson()
if err != nil {
fmt.Println(err)
return
}
id := uuid.NewMD5(id0,[]byte("fssds32"))
fmt.Printf("testv3: %v,%v\n",id,id.Version().String())
}
// v5 NewSHA1(space UUID, data []byte)是根据参数传入的UUID结构体和[]byte再重新转换一次。只要传入参数相同则任意时刻的输出也相同。
func testv5() {
id0,err := uuid.NewDCEPerson()
if err != nil {
fmt.Println(err)
return
}
id := uuid.NewSHA1(id0,[]byte("fssds32"))
fmt.Printf("testv5: %v,%v\n",id,id.Version().String())
}
func main() {
for i:=0; i<2; i++ {
testv1()
}
fmt.Println("--------------------")
for i:=0; i<2; i++ {
testv4()
}
fmt.Println("--------------------")
for i:=0; i<2; i++ {
testv2G()
}
fmt.Println("--------------------")
for i:=0; i<2; i++ {
testv2P()
}
fmt.Println("--------------------")
for i:=0; i<2; i++ {
testv3()
}
fmt.Println("--------------------")
for i:=0; i<2; i++ {
testv5()
}
fmt.Println("--------------------")
}
结论:
v1,v4都是每次生成一个唯一的ID,而v1同一时刻的输出非常相似,v1末尾nodeID部分用的都是mac地址,前面time的mid,high以及clock序列都是一样的,只有time-low部分不同。
v4加入了随机数,对各个部分都进行了随机处理,同一时刻的输出差别很大。
v2 NewDCEGroup()根据os.Getgid取到的用户组ID来生成uuid,同一时刻的输出是相同的。
v2 NewDCEPerson()根据os.Getuid取到的用户ID来生成uuid,同一时刻的输出也是相同的。
v3 NewMD5(space UUID, data []byte)是根据参数传入的UUID结构体和[]byte再重新转换一次。只要传入参数相同则任意时刻的输出也相同。
v5 NewSHA1(space UUID, data []byte)是根据参数传入的UUID结构体和[]byte再重新转换一次。只要传入参数相同则任意时刻的输出也相同。