go言語でUUIDを生成する方法はありますか


109

次のようなコードがあります。

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
この答えは今よりふさわしいようです。
ViKiG 2019

回答:


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範囲内のランダムなバイトを返しますが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

23
特に、このアプローチは遅いです。2012 MacBook Airでは、この戦略は170 uuids /秒しか生成できません。
ジェイテイラー

12
そして、nu7hatch / gouuidライブラリを使用して、172,488個のuuid /秒を生成することができました。
ジェイテイラー

2
u[6]u[8]バイトの適切な説明。
Chowey 2014年

3
私のシステム(Ubuntu 15.10)では、改行文字を削除するために、strings.Trim(string(out))を介してコマンド出力を実行する必要もありました。それ以外の場合は、末尾として入力されましたか?ファイルシステムの文字。
gregtczap 2016

39
存在するかもしれないし存在しないかもしれない外部プログラムを呼び出すことは、このかなり単純なタスクを実行するための恐ろしい方法です。
Timmmm 2016

96

go-uuidライブラリを使用してUUIDを生成できます。これは次のようにインストールできます:

go get github.com/nu7hatch/gouuid

ランダムな(バージョン4)UUIDを生成することができます:

import "github.com/nu7hatch/gouuid"

...

u, err := uuid.NewV4()

返されるUUIDタイプは16バイトの配列なので、バイナリ値を簡単に取得できます。また、そのString()メソッドを介して標準の16進文字列表現を提供します。

また、有効なバージョン4 UUIDも生成するように見えるコードです。最後に実行するビット単位の操作により、UUIDのバージョンフィールドとバリアントフィールドが設定され、バージョン4として正しく識別されます。これは、ランダムなUUIDを他のアルゴリズムで生成されたUUIDと区別するために行われます(たとえば、MACアドレスと時間に基づくバージョン1 UUID)。


2
@Flimzyは、自分が何をしているのかわからない場合に当てはまります。不要な依存関係を導入することは常に悪いことです。
Erik Aigner、2015

31
@ErikAigner 50行である限り、考えたり、書いたり、テストしたりする必要はありません。ありがとうございました。他にやるべきことがあり、それからホイールを再発明します。
RickyA、2015年

3
このライブラリは、実際にはRFC4122に準拠していないように見えます:github.com/nu7hatch/gouuid/issues/28(2016年
Charles L.

1
@ErikAignerがホイールを再発明することも、やや不必要です。ライブラリが存在し、それをうまくやっているのなら、それを行う方法を学ぶためにそれをやっているのではなく、なぜ自分でやる必要があるのか​​。
サー

4
@ErikAigner私はそのリデュールを見つけただけです。コードを調べてそれがうまく機能することを確認して、自分でやる必要がある理由がわかっている場合は、開発時間とコストを浪費するだけでなく、あなたが何をしているか完全に知らない場合、潜在的にバグまたは単に間違った実装をもたらすでしょう、これらのライブラリは通常彼らが何をしているのかを知っている人々になされます。新人サードパーティのライブラリを使用するには、単に最初のコードを調べ、それが動作すると想定していないと、その唯一のルーキー...ではありません
サー・

70

go-uuidライブラリーは、RFC4122に準拠していません。バリアントビットが正しく設定されていません。これを修正するためにコミュニティメンバーによっていくつかの試みがありましたが、修正のプルリクエストは受け入れられていません。

ライブラリに基づいて書き直したGo uuidライブラリを使用して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
このパッケージが好きです。私はすべてのアプリケーションに公式に採用しました。nu7hatchパッケージがRFC4122に準拠していないことがわかりました。
Richard Eng 2014

+1同意。アップデートと印刷/フォーマットの拡張機能はすでに含まれています。
eduncan911 2014

4
免責事項がありませんか?:p
chakrit 2014

3
「下」のライブラリとは何ですか?SOで上と下を使用することは、すぐに変わる可能性があるため、避けてください。
Stephan Dollberg、2015年

また、同等のsatori / go.uuidもあります。まだ試していませんが、nu7hatchの死んだプロジェクトの代わりとして使用します...
shadyyx

52

「crypto / rand」は、ランダムバイト生成用のクロスプラットフォームパッケージです。

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
pseudo_uuidMACアドレスや他にRFC4122で指定されているものなど、ランダムでない識別子がないためです。したがって、実際にはよりランダムです。
Xeoncross 2017

2
いい答えだ; 私はstackoverflow.com/a/48134820/1122270でそれを展開しました、そして多くの人々は実際には特にUUIDを使用する必要がないと思います(自分のランダムに使用する必要があると思っていたsha1 / sha256も- idの問題)、しかし、ランダムで一意の何かが単に必要であり、サンプルはソリューションの良いスタートを提供します
cnst

ありがとう!十分にシンプル
Karl Pokus

1.これは、単に使用して、任意の標準的な2に準拠していない%xバイト値以下128以上の問題を持っている、あなたはすなわち、パディングを適用する必要がある%04xバイトのペアのために
ジャック

38

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


1
godocは使用を推奨していますNew()し、それは同等ですuuid.Must(uuid.NewRandom())
ジム・

@ジム:あなたは正しいです!私はそれに応じて私の答えを更新しました。
Shutefan

New()は「致命的」になる場合があることに注意してください(場合によっては問題ありません)。プログラムを致命的にしたくない場合は、uuid.NewRandom()を使用してください。これにより、UUIDとエラーが返されます。
Tomer

@Tomer:true!これは実際にはどのような状況で発生するのでしょうか。これはコードの関連部分です:github.com/google/uuid/blob/…デフォルトでは、リーダーはrand.Readerです。エラーが返されるかどうか、またはこれがカスタムリーダーでのみ発生するかどうかは
わかり

1
こんにちは@shutefan-私はそれがまれであることに同意します。rand.Readerはカーネル関数を呼び出します(golang.org/src/crypto/rand/rand.go)。これらは特定のシナリオで失敗する場合があります。
Tomer


12

ラス・コックスの投稿から

公式ライブラリはありません。エラーチェックを無視して、これはうまくいくようです:

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し、プレイグラウンド内のすべてのゼロのみを返します。ローカルで正常に動作するはずです。

同じスレッドで、他のいくつかのメソッド/参照/パッケージが見つかりました。


12
ただし、これは有効なUUIDを生成しません。バージョン4のUUID(ランダムデータに基づくタイプ)では、ランダムでないUUID形式との競合を避けるために、いくつかのビットを特定の方法で設定する必要があります。
James Henstridge、2013

4
import "crypto/rand"私の意見では使用するのが良いですが、+ 1しuuid := fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])ます。OPのコードと組み合わせると、これはうまく機能します。
Chowey 2014年

2
crypto / randパッケージの使用:play.golang.org/p/7JJDx4GL77。zzzzのコードはcrypt / randの機能を実行しますが、/ dev / urandom(Windows)をサポートしないプラットフォームも対象としています。
2014年

これはプラットフォーム固有であることに注意してください
Dan Esparza

2
@Matt:問題は、他のUUID形式が他の権限に委任することで一意性を取得し(たとえば、イーサネットMACアドレスが一意であること)、それを他の何か(たとえば、時間とカウンター)と組み合わせることです。V4として正しくフォーマットされていないランダムなUUIDを生成すると、システムが脆弱になります。
James Henstridge、2017

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 

4

gorandのパッケージには、その正規の文字列表現(「XXXXXXXXXXXX-XXXXXXXX-XXXXXXXXXXXX」)でのバージョン4を返すUUID方法(ランダムに生成)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)
} 

4

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

4
マルチプラットフォームアプリケーションに使用されるプログラミング言語のホストプラットフォームに直接依存することは、外部依存よりも悪いため、反対票が投じられました。
Byebye 2018

1
プログラミング言語はマルチプラットフォームにすることができますが、他のプラットフォームにはない、Linux固有の非常に一般的なソリューションであるため、これは有効な応答IMOです。
トン

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
}

2
マルチプラットフォームアプリケーションに使用されるプログラミング言語のホストプラットフォームに直接依存することは、外部依存よりも悪いため、反対票が投じられました。
Byebye 2018

1
@Byebye、なぜあなたは自分自身を、この質問に与えられたすべての回答をざっと見て「システムに依存する」すべてに反対票を投じる「何が悪い」(そして何が悪いではない)かを決定する権威と考えるのだろうか?これらの回答は、すべての可能な選択肢の地平線を広げると、b))に与えられた集合的に提示する全体像を。だから、子供っぽく「SOをする」のをやめて、行動する前に考えてください。
kostix 2018

短い答え。保守可能なコードを書く。回答を別のプラットフォームに移植することはできません。したがって、OPがアプリケーションを別のプラットフォームに移動することを選択した場合、アプリケーションは機能しなくなります。私は、プラットフォームに依存しないコードを書いた人たちと公平にシェアしてきました。コードがまったく不要で、それだけの価値があるよりも問題が発生します。自分だけのコードを書くのではありません。あなたはあなたが去った後にそれを維持する人々のためにコードを書きます。そのため、この回答は適切ではありません。アドホミネムに頼って子供っぽいと呼ぶ理由はない。
Byebye 2018

1
@バイバイ、私は過剰反応したので、攻撃を許してください。私はあなたの理由を確信していませんが、おそらく「同意しないことに同意します」というケースです。
kostix 2018

1

このライブラリは、uuidの生成と解析の標準です。

https://github.com/pborman/uuid


Google独自のライブラリ(github.com/google/uuid)は、部分的にgithub.com/pborman/uuidに基づいていることに注意してください。このgithub.com/pborman/uuidは、Googleが行った変更の一部を組み込んでいます。ただし、申し立てによると、これらのプロジェクトのいずれかに貢献したい場合は、Contributor License Agreement(CLA)に署名する(または署名している)必要があります。これは明らかに、回答が追加された2015年8月の場合は当てはまりませんでした。@pbormanはこれを2016年2月16日にのみ追加しました。
Gwyneth Llewelyn
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.