フラミナル

考え方や調べたことを書き殴ります。IT技術系記事多め

【Go】runeについて理解する(サンプルあり)

f:id:lirlia:20210321183729p:plain

結論

  • runeはGoにおける型の1種類
  • rune型を用いることで、文字列を1文字づつ扱うことができる

前提知識

まず最初に文字コード(コードポインタ)や文字集合と符号化方式について理解しましょう。

こちらの記事にまとめておきました。

blog.framinal.life

Golangにおける文字の扱い

qiita.com

この記事で詳しく書かれていますが、以下のようなコードを実行すると227 129 130が出力されます。

s := "あ"

for i := 0; i < len(s); i++ {
    b := s[i]      // byte
    fmt.Println(b)
}

出力:
227
129
130

直感で考えたり、他の言語だったりするとと表示されるので違和感があると思います。

GoではString型に対してSliceでアクセスを行うと、その文字が格納されているByte値を出力します。

s := "あ"

for i := 0; i < len(s); i++ {
    b := s[i]             // byte
    fmt.Printf("%x\n", b) 
}

出力:
e3
81
82

このように%xをつけて16進数で表示するようにすると、UTF-8で表現されたという文字が出力されることがわかりやすいと思います。

つまりまとめると、あいうえおみたいな文字列を1文字ごとにループで回すような処理をするときにSliceでIndexアクセスをさせると予想に反してバイト値へのアクセスになってしまうということです。

runeについて

これを回避するために使えるのがrune型です。rangeをつかってループを回すことで変数rにはrune型の値が入ります。

s = "あいうえお"

for _, r := range s {
    // rune
    fmt.Println(r)
}

出力:
12354
12356
12358
12360
12362

しかしrune型は対象の文字列のコードポイントを表示するものになるので、「あ」とか「い」が表示されるわけではなくその文字に割り当てられている数字が表示されます。

ややこしいことに、このとき表示される数字は「Unicodeの番号を10進数に変換したもの」です。例えば「あ」のUnicode番号は「U+3042」で、これを10進数表記に変更すると「12354」になります。

rune型の数字を元の文字に戻すにはstring()を使ってあげましょう。 するとこのように出力することができます。

fmt.Println("---")
for _, r := range s {
    // rune
    fmt.Println(string(r))
}

出力:
あ
い
う
え
お

ということでここまでがrune型の説明でした!