172 votes

Existe-t-il une méthode pour générer un UUID avec le langage Go ?

J'ai un code qui ressemble à ceci :

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)

Il renvoie une chaîne de caractères d'une longueur de 32, mais je ne pense pas qu'il s'agisse d'un UUID valide. S'il s'agit d'un vrai UUID, pourquoi est-ce un UUID, et à quoi sert le code qui modifie la valeur de u[8] y u[6] ?

Existe-t-il une meilleure façon de générer des UUID ?

1 votes

Le présent répondre semble plus approprié aujourd'hui.

116voto

James Henstridge Points 10695

Vous pouvez générer des UUID à l'aide de la fonction go-uuid bibliothèque. Elle peut être installée avec :

go get github.com/nu7hatch/gouuid

Vous pouvez générer des UUIDs aléatoires (version 4) avec :

import "github.com/nu7hatch/gouuid"

...

u, err := uuid.NewV4()

Les personnes renvoyées UUID est un tableau de 16 octets, ce qui permet de récupérer facilement la valeur binaire. Il fournit également la représentation standard de la chaîne hexadécimale par l'intermédiaire de sa fonction String() méthode.

Le code que vous avez semble également générer un UUID version 4 valide : la manipulation bit à bit que vous effectuez à la fin définit correctement les champs version et variante de l'UUID. l'identifier comme étant la version 4 . Cela permet de distinguer les UUID aléatoires de ceux générés par d'autres algorithmes (par exemple, les UUID de la version 1 basés sur votre adresse MAC et l'heure).

2 votes

@Flimzy pour les personnes qui ne savent pas ce qu'elles font, c'est très probablement vrai. Introduire des dépendances inutiles est toujours une mauvaise chose.

0 votes

@ErikAigner : Il y a beaucoup d'arguments valables et de raisons pour les deux. Ils se résument tous aux mêmes raisons d'utiliser ou de ne pas utiliser les bibliothèques pour quoi que ce soit, et il n'est pas approprié de les rappeler ici. Mais suggérer que quelqu'un a tort de prendre une décision plutôt qu'une autre est également inapproprié.

0 votes

50 lignes de code pour chaque version d'UUID existante, c'est loin d'être une "bibliothèque"... mais peu importe.

77voto

twinj Points 156

En go-uuid n'est pas conforme à la norme RFC4122. Les bits de variante ne sont pas définis correctement. Les membres de la communauté ont tenté à plusieurs reprises de corriger ce problème, mais les pull requests pour la correction ne sont pas acceptées.

Vous pouvez générer des UUID en utilisant la bibliothèque Go uuid que j'ai réécrite en me basant sur la bibliothèque go-uuid bibliothèque. Plusieurs corrections et améliorations ont été apportées. Il peut être installé avec :

go get github.com/twinj/uuid

Vous pouvez générer des UUIDs aléatoires (version 4) avec :

import "github.com/twinj/uuid"

u := uuid.NewV4()

Le type d'UUID renvoyé est une interface et le type sous-jacent est un tableau.

La bibliothèque génère également les UUIDs v1 et génère correctement les UUIDs v3 et 5. Il existe plusieurs nouvelles méthodes pour faciliter l'impression et le formatage, ainsi que de nouvelles méthodes générales pour créer des UUID à partir de données existantes.

4 votes

J'aime ce paquet. Je l'ai officiellement adopté pour toutes mes applications. J'ai découvert que le paquet nu7hatch n'était pas conforme à la RFC4122.

0 votes

+1 D'accord, les mises à jour et les extensions d'impression/formatage sont déjà incluses.

4 votes

Avis de non-responsabilité manquant ? :p

62voto

Ken Cloud Points 11

"crypto/rand" est un pkg multiplateforme pour la génération d'octets aléatoires.

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
}

3 votes

pseudo_uuid parce qu'il manque les identifiants non aléatoires comme l'adresse MAC et tout ce qui est spécifié dans la RFC4122 ? Il s'agit donc en fait d'un más aléatoire.

2 votes

Bonne réponse ; je l'ai développée à stackoverflow.com/a/48134820/1122270 et je pense qu'un

0 votes

T

34voto

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

Ces lignes limitent les valeurs des octets 6 et 8 à une plage spécifique. rand.Read renvoie des octets aléatoires dans l'intervalle 0-255 qui ne sont pas toutes des valeurs valides pour un UUID. D'après ce que j'ai pu constater, cela devrait être fait pour toutes les valeurs de la tranche.

Si vous êtes sous linux, vous pouvez également appeler /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)
}

Ce qui donne :

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

26 votes

Cette approche est particulièrement lente ; sur un Macbook Air 2012, cette stratégie ne peut produire que 170 uuids/seconde.

12 votes

Et en utilisant la bibliothèque nu7hatch/gouuid, j'ai pu générer 172 488 uuids/seconde.

2 votes

Bonne explication de la u[6] y u[8] des octets.

12voto

zzzz Points 23017

Extrait de l'article de Russ Cox poste :

Il n'existe pas de bibliothèque officielle. Ignorer la vérification des erreurs, cela semble fonctionner correctement :

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 : Dans la version originale, antérieure à Go 1, la première ligne était :

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

Ici qu'il compile et exécute, seulement /dev/urandom renvoie tous les zéros du terrain de jeu. Cela devrait fonctionner correctement au niveau local.

Dans le même fil de discussion, d'autres méthodes/références/paquets ont été trouvés.

15 votes

Cela ne générera cependant pas un UUID valide : les UUID de la version 4 (le type basé sur des données aléatoires) exigent que quelques bits soient définis d'une certaine manière afin d'éviter tout conflit avec les formats UUID non aléatoires.

4 votes

Mieux vaut utiliser import "crypto/rand" à mon avis, mais +1 pour uuid := fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:]) . Combiné avec le code de l'OP, cela fonctionne très bien.

2 votes

Utilisation du paquet crypto/rand : play.golang.org/p/7JJDx4GL77 Le code de zzzz fait la même chose que crypt/rand, sauf qu'il couvre également les plates-formes qui ne supportent pas /dev/urandom (Windows).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X