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

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

このコミットは、Go言語の標準ライブラリの一部であるunicode/utf8パッケージ内のutf8.String型を、実験的なパッケージを格納するexp/utf8stringパッケージへ移動する変更を記録しています。この移動は、Go 1のリリース準備の一環として行われ、特定の機能がまだ安定していない、あるいは将来的に変更される可能性があることを示すためにexpディレクトリに配置されるというGo言語開発における一般的なパターンを反映しています。

コミット

commit 7585aa6ae591a7fecb806d230205f8d12d64c957
Author: Rob Pike <r@golang.org>
Date:   Tue Jan 17 14:21:50 2012 -0800

    utf8.String: move to exp/utf8string.String
    
    R=golang-dev, bradfitz
    CC=golang-dev
    https://golang.org/cl/5528115

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

https://github.com/golang/go/commit/7585aa6ae591a7fecb806d230205f8d12d64c957

元コミット内容

utf8.String: move to exp/utf8string.String

このコミットメッセージは簡潔ですが、utf8.Stringという型がexp/utf8string.Stringという新しい場所へ移動されたことを明確に示しています。これは、Go言語のパッケージ構造における再編成であり、特定の機能の成熟度や安定性に関する開発チームの判断を反映しています。

変更の背景

Go言語では、新しい機能やAPIが標準ライブラリに導入される前に、exp(experimental)ディレクトリ配下のパッケージとして公開されることがあります。これは、コミュニティからのフィードバックを収集し、設計を洗練させるためのテストベッドとして機能します。

このコミットが行われた2012年1月は、Go 1のリリースが間近に迫っていた時期です。Go 1はGo言語にとって最初の安定版リリースであり、後方互換性の保証が非常に重視されました。この文脈において、utf8.String型がexpパッケージに移動された背景には、以下の理由が考えられます。

  1. APIの安定性への懸念: utf8.String型が提供する機能(UTF-8文字列のルーン単位での効率的なインデックスアクセス)は有用であるものの、そのAPI設計や内部実装がGo 1の安定性基準を満たしているか、あるいは将来的な変更の可能性が高いと判断された可能性があります。
  2. 利用状況の評価: expパッケージに置くことで、開発者がこの型を試用し、その有用性や潜在的な問題点についてフィードバックを提供する機会が与えられます。これにより、Goチームは、この型を標準ライブラリのより安定した部分に含めるべきか、あるいは別の形で提供すべきかを判断できます。
  3. Go 1の安定性確保: Go 1のリリースでは、コアライブラリの安定性と後方互換性が最優先されました。まだ実験的な段階にあると見なされる機能をexpに移動することで、Go 1のリリースが遅れることなく、かつ将来的な変更が既存のコードベースに与える影響を最小限に抑えることができます。

doc/go1.htmldoc/go1.tmplの変更からも、Go 1リリース時にいくつかのパッケージがexpに移動されたことが明記されており、utf8.Stringもその一つとして言及されています。これは、Go 1のリリースノートに記載される重要な変更点であったことを示唆しています。

前提知識の解説

このコミットを理解するためには、以下の概念について知っておく必要があります。

  1. Go言語のパッケージシステム: Go言語は、コードをパッケージという単位で整理します。パッケージは、関連する機能や型、関数をまとめたもので、他のパッケージからインポートして利用できます。標準ライブラリは、Go言語に最初から含まれている一連のパッケージです(例: fmt, os, io, unicode/utf8)。
  2. UTF-8エンコーディング: UTF-8は、Unicode文字をバイト列にエンコードするための可変長エンコーディングです。ASCII文字は1バイトで表現されますが、それ以外の文字(日本語、絵文字など)は2バイト以上で表現されます。Go言語の文字列はUTF-8でエンコードされたバイト列として扱われます。
  3. ルーン (Rune): Go言語において、「ルーン」はUnicodeコードポイントを表すために使用される用語です。Goの組み込み型runeint32のエイリアスであり、単一のUnicodeコードポイントを保持します。UTF-8文字列を扱う際、バイト単位ではなくルーン単位で処理することが重要になる場合があります。
  4. unicode/utf8パッケージ: Goの標準ライブラリに含まれるこのパッケージは、UTF-8エンコードされたテキストを操作するための関数を提供します。例えば、RuneCountInStringは文字列内のルーン数をカウントし、DecodeRuneInStringは文字列の先頭から次のルーンとそのバイト幅をデコードします。
  5. expパッケージ: Go言語の公式リポジトリには、x/expという特別なディレクトリが存在します。このディレクトリ内のパッケージは「実験的」と見なされ、将来的にAPIが変更されたり、削除されたりする可能性があります。これらは、標準ライブラリに含める前に、より広範なテストとフィードバックを必要とする機能のために使用されます。
  6. go fix (Gofix): go fixは、Go言語のツールチェーンの一部であり、Goのバージョンアップに伴うAPIの変更に対応するために、古いGoコードを自動的に書き換えるツールです。このコミットの変更ログでは、Gofixまたはコンパイラがexpパッケージの使用について警告するようになることが示唆されています。
  7. ビルドスクリプト: Goのソースコードをコンパイルし、パッケージを生成するためのシェルスクリプト(例: src/buildscript/*.sh)です。これらのスクリプトは、コンパイラ(8g, 6g, 5gなど、それぞれ386, amd64, armアーキテクチャに対応)を呼び出し、Goのソースファイルをオブジェクトファイルに変換し、最終的にパッケージアーカイブ(.aファイル)を作成します。

技術的詳細

このコミットの核心は、unicode/utf8パッケージからutf8.String型をexp/utf8stringパッケージへ移動したことです。この移動は、単なるファイルパスの変更以上の意味を持ちます。

utf8.String型は、Goの標準的なstring型がバイト列として扱われるのに対し、UTF-8文字列をルーン(Unicodeコードポイント)単位で効率的にインデックスアクセスできるように設計されたラッパー型です。通常のGoのstring型では、len(s)はバイト数を返し、s[i]i番目のバイトを返します。しかし、多言語対応のアプリケーションでは、バイト単位ではなく文字(ルーン)単位での操作が頻繁に必要になります。utf8.Stringは、このルーン単位でのアクセスを高速化するために、文字列の非ASCII部分の開始位置やルーン数をキャッシュするなどの最適化を行っていました。

コミットの変更点を見ると、src/pkg/unicode/utf8/string.gosrc/pkg/unicode/utf8/string_test.goがそれぞれsrc/pkg/exp/utf8string/string.gosrc/pkg/exp/utf8string/string_test.goにリネームされています。これにより、utf8.String型は新しいパッケージパスexp/utf8stringの下に置かれました。

string.goのコード変更を見ると、以下の点が注目されます。

  • パッケージ名の変更: package utf8からpackage utf8stringに変更されています。
  • unicode/utf8のインポート: exp/utf8stringパッケージ内で、元のunicode/utf8パッケージの関数(RuneCountInString, DecodeRuneInString, DecodeLastRuneInString, RuneSelfなど)が引き続き使用されるため、import "unicode/utf8"が追加されています。これは、utf8.StringがUTF-8の基本的な操作をunicode/utf8パッケージに依存していることを示しています。
  • 関数呼び出しのプレフィックス追加: RuneSelf, RuneCountInString, DecodeRuneInString, DecodeLastRuneInStringといった関数呼び出しに、utf8.プレフィックスが追加されています。これは、utf8.Stringが自身のパッケージ(utf8string)ではなく、インポートしたunicode/utf8パッケージからこれらの関数を呼び出すことを明確にしています。

ビルドスクリプト(src/buildscript/*.sh)の変更は、src/pkg/unicode/utf8パッケージのビルドコマンドから./string.goが削除されたことを示しています。これは、string.goがもはやunicode/utf8パッケージの一部ではないため、ビルド対象から外されたことを意味します。

src/pkg/exp/utf8string/Makefileの新規追加は、新しいexp/utf8stringパッケージをビルドするための設定ファイルが作成されたことを示しています。これにより、Goのビルドシステムがこの新しい実験的パッケージを認識し、コンパイルできるようになります。

test/alias.goの変更は、utf8.String型がもはや存在しないため、その使用箇所を削除しています。これは、この型が標準ライブラリから削除され、expパッケージに移動したことによる直接的な影響です。

この変更は、Go 1のリリースにおけるAPIの安定化戦略の一環として、utf8.Stringがまだ「実験的」な段階にあると判断されたことを明確に示しています。これにより、Go 1のユーザーは、この型が将来的に変更される可能性があることを認識し、プロダクションコードでの使用を慎重に検討するよう促されます。

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

このコミットにおけるコアとなるコードの変更は、主に以下のファイルのリネームと内容の修正です。

  1. src/pkg/unicode/utf8/string.go から src/pkg/exp/utf8string/string.go へのリネームと内容変更

    • パッケージ宣言が package utf8 から package utf8string に変更。
    • unicode/utf8 パッケージのインポートが追加。
    • RuneSelf, RuneCountInString, DecodeRuneInString, DecodeLastRuneInString などの関数呼び出しに utf8. プレフィックスが追加され、unicode/utf8 パッケージの関数を明示的に参照するように変更。
  2. src/pkg/unicode/utf8/string_test.go から src/pkg/exp/utf8string/string_test.go へのリネームと内容変更

    • パッケージ宣言が package utf8_test から package utf8string に変更。
    • テストコード内で使用されている RuneCountInStringutf8. プレフィックスが追加。
  3. src/pkg/exp/utf8string/Makefile の新規追加

    • exp/utf8string パッケージをビルドするためのMakefileが作成されました。
  4. src/pkg/unicode/utf8/Makefile の修正

    • GOFILES リストから string.go が削除されました。
  5. src/buildscript/*.sh ファイル群の修正

    • 各プラットフォームのビルドスクリプトにおいて、src/pkg/unicode/utf8 パッケージのコンパイルコマンドから string.go が削除されました。
  6. test/alias.go の修正

    • utf8.String 型の使用箇所が削除されました。

コアとなるコードの解説

src/pkg/unicode/utf8/string.goからsrc/pkg/exp/utf8string/string.goへの変更は、utf8.String型がGoの標準ライブラリの安定した部分から、実験的な部分へと移されたことを示しています。

元のstring.goファイルは、unicode/utf8パッケージの一部として、Stringという構造体を定義していました。この構造体は、Goの組み込みstring型をラップし、UTF-8文字列のルーン単位での効率的なインデックスアクセスを提供することを目的としていました。具体的には、Initメソッドで文字列を初期化する際に、文字列がASCII文字のみで構成されているか、あるいは非ASCII文字が含まれているかを判断し、非ASCII文字が含まれる場合は、その開始バイト位置と文字列全体のルーン数をキャッシュしていました。これにより、Atメソッドで特定のルーンインデックスの文字を取得する際に、毎回文字列全体をスキャンすることなく、効率的にアクセスできるようになっていました。

変更後のsrc/pkg/exp/utf8string/string.goでは、以下の点が重要です。

// Package utf8string provides an efficient way to index strings by rune rather than by byte.
package utf8string

import (
	"errors"
	"unicode/utf8" // <-- ここで元のunicode/utf8パッケージをインポート
)

// ... String struct definition ...

func (s *String) Init(contents string) *String {
	s.bytePos = 0
	s.runePos = 0
	for i := 0; i < len(contents); i++ {
		if contents[i] >= utf8.RuneSelf { // <-- utf8.RuneSelf を明示的に参照
			// Not ASCII.
			s.numRunes = utf8.RuneCountInString(contents) // <-- utf8.RuneCountInString を明示的に参照
			_, s.width = utf8.DecodeRuneInString(contents) // <-- utf8.DecodeRuneInString を明示的に参照
			s.nonASCII = i
			return s
		}
		s.numRunes++
	}
	return s
}

// ... At method and other functions ...
  • パッケージ名の変更: package utf8からpackage utf8stringへの変更は、この型が独立したパッケージとして扱われることを意味します。
  • unicode/utf8の明示的なインポート: utf8.Stringの内部実装は、引き続きGoの標準ライブラリのunicode/utf8パッケージが提供する低レベルのUTF-8操作関数(例: RuneCountInString, DecodeRuneInString, RuneSelf)に依存しています。そのため、新しいexp/utf8stringパッケージ内でこれらの関数を使用するために、import "unicode/utf8"が追加されました。
  • 関数呼び出しのプレフィックス: 以前は同じパッケージ内であったためプレフィックスなしで呼び出されていた関数が、パッケージが分かれたことでutf8.RuneSelfのようにutf8.プレフィックスを付けて明示的に参照されるようになりました。これは、Goのパッケージシステムにおける一般的な慣習です。

この変更は、utf8.Stringが提供する機能が、Goの文字列処理において重要であるものの、そのAPIや実装がまだ最終的な形ではない、あるいはより広範な利用シナリオでのテストが必要であるというGoチームの判断を反映しています。expパッケージに置かれることで、この型はGo 1の安定版リリースから除外され、将来的な変更や改善の余地が残されました。

関連リンク

  • Go言語の公式ドキュメント: https://go.dev/doc/
  • Go 1 Release Notes (関連情報が記載されている可能性): https://go.dev/doc/go1 (このコミットが行われた時期のGo 1リリースノートは、doc/go1.htmldoc/go1.tmplの変更から、この移動について言及していることがわかります。)
  • Goのx/expパッケージに関する情報: https://pkg.go.dev/golang.org/x/exp

参考にした情報源リンク