Go を勉強していると必ず出てくるのが rune という型です。
Go の文字列処理を理解するうえで避けて通れません。
この記事では、Go における文字列と rune の関係を整理していきます。
Go の string 型は UTF-8 のバイト列です。
gos := "あ"
fmt.Println(len(s)) // 3
fmt.Println([]byte(s)) // [227 129 130]
"あ" は Unicode のコードポイント U+3042[227 129 130])で表現されますlen(s) は「文字数」ではなく「バイト数」を返します👉 Go の string は「文字列」ではなく「UTF-8 の生バイト列」と理解するのが正確です。
rune は int32 の別名例:
govar r rune = 'あ'
fmt.Println(r) // 12354 (U+3042)
fmt.Printf("%c\n", r) // あ
'あ' という 文字リテラル は rune 型r は「文字そのもの」ではなく「そのコードポイント(番号)」👉 Go で「1文字」を扱うなら rune を使うのが基本。
| 型 | 中身 | 例 |
|---|---|---|
string | UTF-8 のバイト列 | "あ" → [227 129 130] |
rune | Unicode コードポイント (int32) | 'あ' → 12354 (U+3042) |
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 ではフォーマット指定子によって 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
| 言語 | 文字列の実体 | ループ時の単位 | 注意点 |
|---|---|---|---|
| Java | UTF-16 | char (16bit, UTF-16コードユニット) | サロゲートペアで1文字が2つに分かれる場合あり |
| Python3 | Unicode (抽象的にコードポイント) | 1文字 = コードポイント | len(s) は文字数 |
| Go | UTF-8 バイト列 | rune (コードポイント) | len(s) はバイト数。文字数は len([]rune(s)) |
rune は Unicode の コードポイントを表す int32len(string) は「文字数」ではなく「バイト数」[]rune に変換して扱う👉 「文字列 = バイト列」「文字 = rune(コードポイント)」と理解しておけば、Go での文字列処理はかなり見通しがよくなります。