main.go
package main
import "fmt"
func main() {
samples := []string{"hello", "apple_π!", "これは漢字文字列"} //liststart
for _, sample := range samples {
for i, r := range sample {
fmt.Println(i, r, string(r))
}
fmt.Println()
}
}
1. コードの解説
-
スライスの定義:
samples := []string{"hello", "apple_π!", "これは漢字文字列"}
-
[]string
は文字列のスライスを表します。 -
:=
は短縮変数宣言で、型推論を使用して変数を宣言と同時に初期化します。
-
-
外部ループ:
for _, sample := range samples {
-
range
キーワードを使用してスライスをイテレートします。 -
_
はインデックスを無視するためのブランク識別子です。 -
sample
は各イテレーションで現在の文字列を表します。
-
-
内部ループ:
for i, r := range sample {
- 文字列
sample
に対してrange
を使用します。 -
i
はバイトインデックス、r
は各文字(ルーン)を表します。
- 文字列
-
出力:
fmt.Println(i, r, string(r))
-
i
: バイトインデックス -
r
: 文字のUnicodeコードポイント -
string(r)
: コードポイントを文字列に変換
-
ポイント
- Goの文字列はUTF-8エンコードされたバイト列です。
-
range
で文字列をイテレートすると、Unicodeコードポイント(ルーン)単位で処理されます。 -
i
はバイトインデックスを表すため、マルチバイト文字では連続しない値になることがあります。 -
r
はint32型で、Unicodeコードポイントを表します。
出力結果の解釈
- ASCII文字(例:英語)は1バイトなので、インデックスは1ずつ増加します。
- 非ASCII文字(例:π、漢字)は複数バイトなので、インデックスは1以上増加します。
- コードポイントは各文字のUnicode値を示します。
-
string(r)
は実際の文字を表示します。
2. 出力結果からの考察
- インデックス (i)
- Unicode コードポイント (r)
- 実際の文字 (string(r))
iの値がイレギュラーに見える理由は、Goの文字列がUTF-8エンコーディングを使用しているためです。具体的に説明すると:
-
ASCII文字(例:英語のアルファベット):
これらは1バイトで表現されるため、インデックスは1ずつ増加します。 -
マルチバイト文字(例:絵文字、漢字):
これらは複数バイトで表現されるため、インデックスが1つの文字に対して複数増加することがあります。
考察
-
"hello": 各文字が1バイトなので、インデックスは0から4まで順に増加します。
-
"apple_π!":
- "apple_"までは1バイト文字なので、インデックスは0から5まで順に増加。
- "π"はUTF-8で3バイト使用するため、インデックスが5から6に飛び、次は8になります。
- "!"は1バイト文字なので、インデックスは8のままです。
-
"これは漢字文字列":
各文字が3バイトで表現されるため、インデックスは3ずつ増加します(0, 3, 6, 9, 12, 15, 18)。
このように、Goのrange
ループは文字列をUTF-8エンコードされたバイト列として扱い、各文字(ルーン)の開始バイトのインデックスを返します。そのため、マルチバイト文字を含む文字列では、インデックスが連続的に増加しないように見えるのです。
これは、Goが Unicode を完全にサポートしつつ、メモリ効率の良い UTF-8 エンコーディングを使用していることの結果です。