Есть ли способ генерации UUID с языком go?

У меня есть код, который выглядит так:

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] и u[6].

Есть ли лучший способ генерации UUID?

Ответ 1

u[8] = (u[8] | 0x80) & 0xBF // what the purpose ?
u[6] = (u[6] | 0x40) & 0x4F // what the purpose ?

Эти строки фиксируют значения байтов 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

Ответ 2

Вы можете сгенерировать UUID, используя библиотеку go-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 версии 1 на основе вашего MAC-адреса и времени).

Ответ 3

Библиотека go-uuid НЕ соответствует RFC4122. Вариантные биты установлены неправильно. Было несколько попыток членов сообщества получить это исправление, но запросы на получение исправления не принимаются.

Вы можете сгенерировать UUID, используя библиотеку Go uuid, которую я переписал на основе библиотеки go-uuid. Есть несколько исправлений и улучшений. Это можно установить с помощью

go get github.com/twinj/uuid

Вы можете генерировать случайные (версии 4) UUID с помощью:

import "github.com/twinj/uuid"

u := uuid.NewV4()

Возвращенный тип UUID - это интерфейс, а базовый тип - это массив.

Библиотека также генерирует v1 UUID и правильно генерирует v3 и 5 UUID. Существует несколько новых методов, помогающих в печати и форматировании, а также новые общие методы создания UUID на основе существующих данных.

Ответ 4

"crypto/rand" - это кросс-платформа pkg для генерации случайных байтов

package main

import (
    "crypto/rand"
    "fmt"
)

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

Вы должны использовать Google/UUID https://github.com/google/uuid

package main

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

func main() {
    id, err := uuid.NewUUID()
    if err !=nil {
        // handle error
    }
    fmt.Printf(id.String())
}

Этот пакет соответствует RFC4122 и DCE 1.1

Ответ 7

Существует официальная реализация от Google: https://github.com/google/uuid

Генерация UUID версии 4 работает следующим образом:

package main

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

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

Попробуйте здесь: https://play.golang.org/p/6YPi1djUMj9

Ответ 8

Из Russ Cox post:

Там нет официальной библиотеки. Игнорируя проверку ошибок, похоже, что это будет нормально работать:

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

Примечание. В исходной версии Pre Go 1 первая строка была:

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

Здесь он компилируется и исполняется, только /dev/urandom возвращает все нули на игровой площадке. Должен работать нормально локально.

В том же потоке найдены некоторые другие методы/ссылки/пакеты.

Ответ 9

Как часть спецификации uuid, если вы создаете uuid из случайного, он должен содержать "4" в качестве 13-го символа и "8", "9", "a" или "b" в 17-м (источник).

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

Пакет gorand имеет метод UUID, который возвращает произвольный UUID версии 4 (случайно генерируемый) в его каноническом представлении строки ( "xxxxxxxx- xxxx-xxxx-xxxx-xxxxxxxxxxxx" ) и совместим с RFC 4122.

Он также использует пакет crypto/rand для обеспечения наиболее криптографически безопасного поколения UUID на всех платформах, поддерживаемых Go.

import "github.com/leonelquinteros/gorand"

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

    println(uuid)
} 

Ответ 11

В 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

Ответ 12

В 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
}

Ответ 13

Эта библиотека является нашим стандартом для генерации и анализа uuid:

https://github.com/pborman/uuid