【Go】byte, runeとstring

文字を扱う型、byteとruneはどう違う?

Goでは文字を扱う型としてbyteとruneが、文字列を扱う型としてstringがあります。string型はUTF-8で符号化されたバイト列を保持し、[]byte(s)でバイト列へ変換できます。またruneはユニコードのコードポイントを格納し、[]rune(s)でコードポイント列へ変換できます。ソースコード上では””はstring型、”はrune型として扱われます。

(『みんなのGo言語』)

Go言語で定義されている文字を扱う型、byteとrune。バイト列?コードポイント?とクエスチョンだらけだったのですが、最近ちょっと腑に落ちました。

参考にした記事はこちら。自分なりに要約すると、runeが格納しているコードポイントとは、Unicodeの体系の中で、それぞれの文字に割り当てられたコンピューテーショナルな値のこと。これで何が嬉しいかというと、文字コードの歴史上、後から追加された多バイト文字(漢字・仮名など)も、ちゃんと一字ずつ取得できること。

package main

import "fmt"

func main() {
    en := "This is a pen."  
    bytes_en := []byte(en)
    runes_en := []rune(en)
    fmt.Printf("English byte: %+v\n", string(bytes_en[1]))
    fmt.Printf("English rune: %+v\n", string(runes_en[1]))
    
    ja := "これはペンです"
    bytes_ja := []byte(ja)
    runes_ja := []rune(ja)
    fmt.Printf("Japanese byte: %+v\n", string(bytes_ja[1]))
    fmt.Printf("Japanese rune: %+v\n", string(runes_ja[1]))
}

// 出力結果
// English byte: h
// English rune: h
// Japanese byte: 
// Japanese rune: れ

上のコードでは、アルファベット文字列および日本語文字列について、それぞれbyte, runeスライスをつくり、その2つ目の要素を出力しています。つまり、「文字列の2文字目を出力しよう」としています。が、単純なバイト列だと、多バイト文字である漢字・仮名は「文字の一部」しか出力できず文字化けしてしまいます。一方、rune型だと「ユーザが文字として認識するかたまり(正式には書記素 grapheme と呼ばれます)」を単位として情報が格納されるので、多バイト文字に起因する文字化けを防げる 、というワケです。

参考

【中古】プログラマのための文字コ-ド技術入門 /技術評論社/矢野啓介(単行本(ソフトカバー))価格:652円
(2021/12/15 07:30時点)