Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 10094] ファイルの概要

コミット

  • コミットハッシュ: db33959797ad8ef1e86725db62aafb40297ea725
  • 日付: 2011年10月25日 22:20:02 -0700
  • 作成者: Russ Cox rsc@golang.org
  • コミットメッセージ: "cgo, goyacc, go/build, html, http, path, path/filepath, testing/quick, test: use rune"

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/db33959797ad8ef1e86725db62aafb40297ea725

元コミット内容

このコミットは20個のファイルを変更し、114行の挿入と107行の削除を含む大規模な型変更を実施しました。Russ Cox氏のコメントによると「Nothing terribly interesting here.」(特に興味深いものはここにはない)とされていますが、実際にはGo言語の進化において重要な意味を持つ変更です。

変更の背景

Go 1.0への準備段階(2011年)

このコミットは、Go 1.0の正式リリース(2012年3月)に向けた準備段階で実施されました。Go言語は2009年にGoogleによってオープンソース化され、2011年の時点では活発な開発が続けられていた段階でした。

Unicode処理の統一化

Go 1.0リリースに向けて、Unicode文字処理の標準化が重要な課題となっていました。それまでのコードでは、Unicode文字を表すためにint型が使用されていましたが、これは意味的に不明確で、コードの可読性と保守性を損なう問題がありました。

型安全性の向上

int型をUnicode文字の表現に使用することで、整数演算と文字処理が混在し、プログラマーにとって意図が不明確になる問題が発生していました。より意味的に明確な型の導入が必要でした。

前提知識の解説

Unicode とUTF-8の関係

Unicodeは、世界中の文字を統一的に表現するための文字コード標準です。各文字には「コードポイント」と呼ばれる一意の番号が割り当てられます。

UTF-8は、Unicodeコードポイントを1〜4バイトの可変長で符号化する方式です。ASCII文字(0-127)は1バイトで表現され、他の文字は2〜4バイトで表現されます。

Goにおけるrune型の定義

Go言語では、rune型はint32型の別名(エイリアス)として定義されています:

type rune = int32

この設計により、Unicode文字を表現するのに必要な最大4バイトのデータを保持できます。

文字列処理の複雑さ

Go言語の文字列は、UTF-8エンコードされたバイト列として内部的に表現されます。しかし、プログラマーが文字列を操作する際には、個々のUnicode文字(コードポイント)単位での処理が必要になることが多く、これがバイト単位での処理と混同されやすい原因となっていました。

技術的詳細

変更のスコープ

このコミットは以下の領域に渡って変更を実施しました:

  1. コマンドラインツール: cgogoyacc
  2. 標準パッケージ: go/buildhtmlhttppathpath/filepathtesting/quicksyscall
  3. テストファイル: 様々なテストファイルとサンプルコード

型変更の体系的な実施

変数宣言の変更

// 変更前
var c int
var chars [6]int

// 変更後
var c rune
var chars [6]rune

関数シグネチャの変更

// 変更前
func slashToUnderscore(c int) int

// 変更後
func slashToUnderscore(c rune) rune

スライスと配列の変更

// 変更前
arg := make([]int, len(s))
var entity = map[string]int{...}

// 変更後
arg := make([]rune, len(s))
var entity = map[string]rune{...}

型変換の明示化

// 変更前
numbval = c - '0'

// 変更後
numbval = int(c - '0')

細かな変更点の分析

コードポイントの統一

HTML entityの処理において、Unicode文字を表現するマップがintからruneに変更されました:

// 変更前
var entity = map[string]int{
    "AElig;": '\U000000C6',
    "AMP;":   '\U00000026',
    // ...
}

// 変更後
var entity = map[string]rune{
    "AElig;": '\U000000C6',
    "AMP;":   '\U00000026',
    // ...
}

文字変換関数の修正

CGIパッケージでは、文字変換関数が適切に型を明示するよう修正されました:

// 変更前
func upperCaseAndUnderscore(rune int) int {
    switch {
    case rune >= 'a' && rune <= 'z':
        return rune - ('a' - 'A')
    // ...
    }
}

// 変更後
func upperCaseAndUnderscore(r rune) rune {
    switch {
    case r >= 'a' && r <= 'z':
        return r - ('a' - 'A')
    // ...
    }
}

注目すべきは、変数名もruneからrに変更されていることです。これはruneが予約語となることを見越した変更でした。

コアとなるコードの変更箇所

1. src/cmd/cgo/gcc.go:44

// 変更前
if len(l) < 5 || l[:4] != "#cgo" || !unicode.IsSpace(int(l[4])) {

// 変更後
if len(l) < 5 || l[:4] != "#cgo" || !unicode.IsSpace(rune(l[4])) {

2. src/cmd/goyacc/goyacc.go:115-117

// 変更前
var i, match, c int

// 変更後
var i int
var match, c rune

3. src/pkg/html/entity.go:264

// 変更前
var entity = map[string]int{

// 変更後
var entity = map[string]rune{

4. src/pkg/testing/quick/quick.go:436-440

// 変更前
codePoints := make([]int, numChars)
for i := 0; i < numChars; i++ {
    codePoints[i] = rand.Intn(0x10ffff)
}

// 変更後
codePoints := make([]rune, numChars)
for i := 0; i < numChars; i++ {
    codePoints[i] = rune(rand.Intn(0x10ffff))
}

コアとなるコードの解説

Unicode文字処理の統一

最も重要な変更は、Unicode文字を表現するために一貫してrune型を使用するようにしたことです。これにより:

  1. 意味的明確性: コードを読む人にとって、その変数がUnicode文字を表現していることが明確になります
  2. 型安全性: 整数演算と文字処理が明確に区別されるようになります
  3. 将来の拡張性: Go 1.0以降の型システムの進化に対応できる基盤が構築されます

型変換の明示化

特に重要な変更は、文字リテラルから整数への変換を明示的に行うようにしたことです:

// 変更前(暗黙的な型変換)
numbval = c - '0'

// 変更後(明示的な型変換)
numbval = int(c - '0')

これにより、プログラマーは文字操作と整数操作の境界を明確に認識できるようになります。

テストコードの更新

テストファイルの更新も重要な側面です。特にtest/utf.goでは、UTF-8エンコーディングのテストがrune型を使用するように更新され、Go言語のUnicode処理能力を適切にテストできるようになりました。

関連リンク

参考にした情報源リンク

このコミットは、Go言語の型システムの洗練化と、Unicode文字処理の標準化において重要な役割を果たした変更でした。表面的には地味な変更に見えますが、Go 1.0の成功と、その後のGo言語の発展において欠かせない基盤を構築した重要な変更といえます。