Dyuichi Blog

Goにおける文字列とruneの理解

Go を勉強していると必ず出てくるのが rune という型です。

Go の文字列処理を理解するうえで避けて通れません。

この記事では、Go における文字列と rune の関係を整理していきます。


文字列(string)の正体

Go の string 型は UTF-8 のバイト列です。

gos := "あ"
fmt.Println(len(s))   // 3
fmt.Println([]byte(s)) // [227 129 130]
  • "あ" は Unicode のコードポイント U+3042
  • UTF-8 では 3バイト([227 129 130])で表現されます
  • そのため len(s) は「文字数」ではなく「バイト数」を返します

👉 Go の string は「文字列」ではなく「UTF-8 の生バイト列」と理解するのが正確です。


runeとは何か
  • runeint32 の別名
  • Unicode の コードポイント(文字の番号)を表すために使います

例:

govar r rune = 'あ'
fmt.Println(r)        // 12354 (U+3042)
fmt.Printf("%c\n", r) // あ
  • 'あ' という 文字リテラルrune
  • r は「文字そのもの」ではなく「そのコードポイント(番号)」

👉 Go で「1文字」を扱うなら rune を使うのが基本。


string と rune の違い
中身
stringUTF-8 のバイト列"あ"[227 129 130]
runeUnicode コードポイント (int32)'あ'12354 (U+3042)

for range の挙動

for range で文字列をループすると、UTF-8 を自動的にデコードして rune 単位で取り出します。

gos := "あ"
for i, r := range s {
    fmt.Printf("index %d: rune %c (U+%04X)\n", i, r, r)
}

出力例:

plain textindex 0: rune あ (U+3042)
  • i … 文字が始まる バイト位置
  • r … 文字のコードポイント (rune)

fmt.Printf での出力

fmt.Printf ではフォーマット指定子によって rune の出力方法が変わります。

gos := "あ"
for _, r := range s {
    fmt.Printf("as char: %c\n", r)   // 文字として
    fmt.Printf("as int : %d\n", r)   // 10進数
    fmt.Printf("as hex : %x\n", r)   // 16進数
    fmt.Printf("as U+  : U+%04X\n", r) // Unicode表記風
}

出力:

plain textas char: あ
as int : 12354
as hex : 3042
as U+  : U+3042

他言語との比較
言語文字列の実体ループ時の単位注意点
JavaUTF-16char (16bit, UTF-16コードユニット)サロゲートペアで1文字が2つに分かれる場合あり
Python3Unicode (抽象的にコードポイント)1文字 = コードポイントlen(s) は文字数
GoUTF-8 バイト列rune (コードポイント)len(s) はバイト数。文字数は len([]rune(s))

まとめ
  • Go の文字列は UTF-8 のバイト列
  • rune は Unicode の コードポイントを表す int32
  • len(string) は「文字数」ではなく「バイト数」
  • 文字単位の処理をしたいなら []rune に変換して扱う

👉 「文字列 = バイト列」「文字 = rune(コードポイント)」と理解しておけば、Go での文字列処理はかなり見通しがよくなります。