31634
<https://code.jp.ai/question/155>

上記のサイトを参考にしてIDを生成したいと考えているのですが、Goではどのように実装すれば良いのでしょうか。

考えてみましたが、`md5.Sum(ip)`は`[16]byte`型なので`[:30]`のようにスライスできません。  
golangにもPHPの`substr`のような関数があれば良いのですが、見つかりませんでした。

どのように実装できるかご教授ください。
CC BY-SA 3.0
2017-01-05T07:32:41.387
31633
2017-01-05T09:54:25.767
7232
question
php go
golangで2chのIDを生成したい
* md5ハッシュは16バイト長であると規格で定められています（ただし1バイトを8ビットとします）。 
    * PHPの`md5()`はそれを16進表記に直し、32文字にしています([参考](http://php.net/manual/ja/function.md5.php))。
    * Goの`md5.Sum()`は[]byte型のまま結果が得られます([参考](https://golang.org/pkg/crypto/md5/#Sum))。
  * Goで[]byte型を16進数の文字列に変換したい場合、`fmt.Sprintf`が使えると思います。`%x`や`%X`フォーマットが使えます。 
    * あるいは、`hex.EncodeToString` でも良さそうです([参考](https://golang.org/pkg/encoding/hex/#EncodeToString))。ただしarrayとsliceの違いにご注意ください([参考](https://stackoverflow.com/questions/28886616/convert-array-to-slice-in-go))。
  * 部分文字列は、Unicodeのことを考えると簡単には実装できないことが分かります。そのためGoでは、string型、[]byte型、[]rune型を上手く使い分けています。詳しくは [  
"Strings, bytes, runes and characters in Go - The Go
Blog"](https://blog.golang.org/strings) を見て下さい。

    * 入力される文字列が1バイト文字に限られているのであれば、string型の変数`s`に対して単に`s[i:j]`とすると部分文字列が得られます。
    * そうでない場合は、一旦[]rune型にキャストして操作すると良いです。たとえば`string([]rune(s)[i:j])`といった具合です。
  * 今回の場合に限れば、最初の、[]byte型のハッシュ値の時点で部分列をとる方が簡単です。
CC BY-SA 3.0
2017-01-05T08:49:32.727
31634
2017-01-05T09:00:30.140
2017-05-23T12:38:56.467
-1
19110
31633
answer
詳しい説明は[nekketsuuu さんの回答](https://ja.stackoverflow.com/a/31634/3054)にあるので補足です。

> []byte型のハッシュ値の時点で部分列をとる

これをする場合、質問のように `[:30]`
とやれば失敗しますので、16進表記の文字列に変換すると1バイトが2文字で表現されて要素数が倍になる事を考慮して`[:15]` とします。

ただ、今回は16進表記の文字列（全て ASCII の範囲内）に変換するので、変換後の `string` に対して文字数を使い、`[:30]`
としても大丈夫です。

> 入力される文字列が1バイト文字に限られているのであれば、string型の変数sに対して単にs[i:j]とすると部分文字列が得られます。

とある通りです。

* * *
```

    package main
    
    import (
        "crypto/md5"
        "encoding/hex"
        "fmt"
    )
    
    func main() {
        ip := "192.0.2.0"
        sum := md5.Sum([]byte(ip))
    
        fmt.Printf("sum: %v\n", sum)
        fmt.Printf("len(sum): %d\n", len(sum))
    
        sumPart := sum[:15]
    
        fmt.Printf("sumPart: %v\n", sumPart)
        fmt.Printf("len(sumPart): %d\n", len(sumPart))
    
        sumPartFmt := fmt.Sprintf("%x", sumPart)
    
        fmt.Printf("sumPartFmt: %s\n", sumPartFmt)
        fmt.Printf("len(sumPartFmt): %d\n", len(sumPartFmt))
    
        sumPartHex := hex.EncodeToString(sumPart)
    
        fmt.Printf("sumPartHex: %s\n", sumPartHex)
        fmt.Printf("len(sumPartHex): %d\n", len(sumPartHex))
    }
    
```

出力:

```

    sum: [87 207 62 5 209 246 147 31 76 22 249 16 174 171 96 29]
    len(sum): 16
    sumPart: [87 207 62 5 209 246 147 31 76 22 249 16 174 171 96]
    len(sumPart): 15
    sumPartFmt: 57cf3e05d1f6931f4c16f910aeab60
    len(sumPartFmt): 30
    sumPartHex: 57cf3e05d1f6931f4c16f910aeab60
    len(sumPartHex): 30
    
```
CC BY-SA 3.0
2017-01-05T09:54:25.767
31636
2017-01-05T09:54:25.767
2017-04-13T12:52:39.113
-1
3054
31633
answer