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

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

このコミットは、Go言語の標準ライブラリの一部である src/lib/unicode/letter.go ファイルに対する変更です。このファイルは、Unicode文字のプロパティ、特に文字がアルファベットであるか、大文字であるかなどを判定するためのデータと関数を提供します。具体的には、Unicodeのコードポイント範囲を定義するRange構造体、大文字の範囲を定義するUpper、一般的な文字の範囲を定義するLetterといった変数、そしてそれらの範囲内に特定のルーン(Unicodeコードポイント)が含まれるかを判定するIs関数、IsUpper関数、IsLetter関数などが含まれています。

コミット

  • コミットハッシュ: b18e4184100e18c50b88d009487dd7a2841d093a
  • 作者: Rob Pike r@golang.org
  • コミット日時: 2009年3月6日 金曜日 03:22:02 -0800
  • 変更ファイル: src/lib/unicode/letter.go

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

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

元コミット内容

    document unicode, such as it is
    
    R=rsc
    DELTA=18  (9 added, 0 deleted, 9 changed)
    OCL=25817
    CL=25832

変更の背景

このコミットは、Go言語の初期開発段階におけるUnicodeサポートのドキュメント化と、それに伴うAPIの改善を目的としています。

主な変更点は以下の通りです。

  1. ドキュメントの追加: unicodeパッケージ、Range構造体、UpperLetter変数、IsUpperIsLetter関数など、主要な要素にコメントが追加され、その役割が明確化されました。これは、Go言語の設計哲学において、コードの可読性とドキュメントの重要性が高く評価されていることを反映しています。
  2. Range構造体のフィールド名変更: Range構造体のフィールド名が lo, hi, stride から Lo, Hi, Stride へと変更されました。これはGo言語の可視性ルール(エクスポートルール)に則った変更であり、これらのフィールドがパッケージ外部からアクセス可能になることを意味します。これにより、unicodeパッケージを利用する他のパッケージが、Range構造体の内部データに直接アクセスできるようになり、より柔軟な処理が可能になります。
  3. コードの整合性: フィールド名変更に伴い、Is関数内の参照も新しいフィールド名に更新され、コード全体の整合性が保たれています。

Go言語は、その設計当初からUnicodeを完全にサポートすることを目標としており、このコミットはその初期段階におけるUnicode関連コードの整備の一環として行われました。特に、Goの設計者の一人であるRob Pike氏によるコミットであることから、Go言語の設計思想が色濃く反映されていると言えます。

前提知識の解説

Unicodeとコードポイント

Unicodeは、世界中のあらゆる文字を統一的に扱うための文字コードの国際標準です。各文字には一意の「コードポイント」と呼ばれる数値が割り当てられています。例えば、'A'はU+0041、'あ'はU+3042といった形で表現されます。Go言語では、文字列はUTF-8でエンコードされ、個々の文字は「ルーン(rune)」として扱われます。ルーンはint32型で表現され、Unicodeのコードポイントに対応します。

Go言語の可視性ルール(エクスポート)

Go言語には、パッケージ内外からの識別子(変数、関数、構造体、フィールドなど)のアクセスを制御するシンプルなルールがあります。

  • エクスポートされた識別子: 識別子の名前が大文字で始まる場合、その識別子はパッケージ外部からアクセス可能です(エクスポートされている)。
  • エクスポートされていない識別子: 識別子の名前が小文字で始まる場合、その識別子はパッケージ内部からのみアクセス可能です(エクスポートされていない)。

このコミットにおけるRange構造体のフィールド名変更(lo -> Loなど)は、この可視性ルールに直接関係しています。小文字だったフィールドが大文字に変更されたことで、これらのフィールドがunicodeパッケージの外部からも参照・利用できるようになりました。

Go言語のunicodeパッケージ

Go言語の標準ライブラリには、Unicode文字のプロパティを扱うためのunicodeパッケージが含まれています。このパッケージは、特定のルーンが数字であるか、文字であるか、空白文字であるか、大文字であるか、小文字であるかなどを判定する関数を提供します。また、Unicodeのカテゴリ情報やスクリプト情報なども提供し、多言語対応のアプリケーション開発を支援します。

Range構造体

unicodeパッケージ内で定義されているRange構造体は、Unicodeのコードポイントの連続した範囲を表現するために使用されます。

type Range struct {
	Lo     int // 範囲の開始コードポイント(含む)
	Hi     int // 範囲の終了コードポイント(含む)
	Stride int // コードポイントの増分(通常は1)
}

この構造体は、特定の文字の集合(例: 大文字、数字など)を効率的に表現するために利用されます。Strideは、範囲内のコードポイントが等間隔で並んでいる場合にその間隔を示します。例えば、Strideが1であれば、LoからHiまでの全てのコードポイントが含まれます。

技術的詳細

このコミットの技術的な変更は、主にsrc/lib/unicode/letter.goファイル内の以下の点に集約されます。

  1. パッケージコメントの追加:

    --- a/src/lib/unicode/letter.go
    +++ b/src/lib/unicode/letter.go
    @@ -10,14 +10,19 @@
     // link in only the tables that are used by the program,
     // etc.
     
    +// This package provides data and functions to test some properties of Unicode code points.
    +// It is rudimentary but will improve.
     package unicode
    

    package unicodeの直前に、このパッケージがUnicodeコードポイントのプロパティをテストするためのデータと関数を提供すること、そしてまだ基本的な機能しか持たないが今後改善される予定であることが明記されました。これは、Go言語のドキュメンテーション規約に則ったもので、パッケージの目的を明確に示します。

  2. Range構造体のフィールド名変更とコメント追加:

    --- a/src/lib/unicode/letter.go
    +++ b/src/lib/unicode/letter.go
    @@ -10,14 +10,19 @@
     // link in only the tables that are used by the program,
     // etc.
     
    +// This package provides data and functions to test some properties of Unicode code points.
    +// It is rudimentary but will improve.
     package unicode
     
    +// The representation of a range of Unicode code points.  The range runs from Lo to Hi
    +// inclusive and has the specified stride.
     type Range struct {
    -	lo int;
    -	hi int;
    -	stride int;
    +	Lo int;
    +	Hi int;
    +	Stride int;
     }
    

    Range構造体のフィールド名がlo, hi, strideからLo, Hi, Strideへと変更されました。これにより、これらのフィールドはエクスポートされ、unicodeパッケージの外部から直接アクセスできるようになりました。また、各フィールドの役割を説明するコメントが追加され、構造体の意図がより明確になりました。

  3. 変数および関数へのコメント追加:

    --- a/src/lib/unicode/letter.go
    +++ b/src/lib/unicode/letter.go
    @@ -150,6 +155,7 @@ var Upper = []Range{\n     	Range{0x1d7ca, 0x1d7ca, 1},\n     }\n     \n    +// Letter is the set of Unicode letters.\n     var Letter = []Range {\n     	Range{0x0041, 0x005a, 1},\n     	Range{0x0061, 0x007a, 1},\
    

    Upper変数とLetter変数に、それぞれがUnicodeの大文字と文字の集合であることを示すコメントが追加されました。

    --- a/src/lib/unicode/letter.go
    +++ b/src/lib/unicode/letter.go
    @@ -559,10 +566,12 @@ func Is(ranges []Range, rune int) bool {\n     	return false;\n     }\n     \n    +// IsLetter reports whether the rune is an upper case letter.\n     func IsUpper(rune int) bool {\n     	return Is(Upper, rune);\n     }\n     \n    +// IsLetter reports whether the rune is a letter.\n     func IsLetter(rune int) bool {\n     	return Is(Letter, rune);\n     }\
    

    IsUpper関数とIsLetter関数に、それぞれがルーンが大文字であるか、文字であるかを報告することを示すコメントが追加されました。

  4. Is関数の内部ロジックの更新:

    --- a/src/lib/unicode/letter.go
    +++ b/src/lib/unicode/letter.go
    @@ -525,18 +531,19 @@ var Letter = []Range {\n     	Range{0x2f800, 0x2fa1d, 1},\n     }\n     \n    +// Is tests whether rune is in the specified table of ranges.\n     func Is(ranges []Range, rune int) bool {\n     	// common case: rune is ASCII or Latin-1\n     	if rune < 0x100 {\n     		for i := 0; i < len(ranges); i++ {\n     			r := ranges[i];\n    -			if rune > r.hi {\n    +			if rune > r.Hi {\n     				continue;\n     			}\n    -			if rune < r.lo {\n    +			if rune < r.Lo {\n     				return false;\n     			}\n    -			return (rune - r.lo) % r.stride == 0;\n    +			return (rune - r.Lo) % r.Stride == 0;\n     		}\n     		return false;\n     	}\
    

    Is関数内でRange構造体のフィールドを参照している箇所が、r.lo, r.hi, r.strideからr.Lo, r.Hi, r.Strideへと変更されました。これは、Range構造体のフィールド名変更に合わせた修正であり、コードの機能的な変更はありません。Is関数は、与えられたルーンが指定されたRangeスライス内のいずれかの範囲に含まれるかを効率的に判定するための二分探索アルゴリズムを使用しています。

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

このコミットにおけるコアとなるコードの変更箇所は、主にsrc/lib/unicode/letter.goファイル内の以下の部分です。

  1. Range構造体の定義変更:

    --- a/src/lib/unicode/letter.go
    +++ b/src/lib/unicode/letter.go
    @@ -10,14 +10,19 @@
     // link in only the tables that are used by the program,
     // etc.
     
    +// This package provides data and functions to test some properties of Unicode code points.
    +// It is rudimentary but will improve.
     package unicode
     
    +// The representation of a range of Unicode code points.  The range runs from Lo to Hi
    +// inclusive and has the specified stride.
     type Range struct {
    -	lo int;
    -	hi int;
    -	stride int;
    +	Lo int;
    +	Hi int;
    +	Stride int;
     }
    

    Range構造体のフィールド名が小文字から大文字に変更され、コメントが追加されました。

  2. Is関数内のRangeフィールド参照の更新:

    --- a/src/lib/unicode/letter.go
    +++ b/src/lib/unicode/letter.go
    @@ -525,18 +531,19 @@ var Letter = []Range {\n     	Range{0x2f800, 0x2fa1d, 1},\n     }\n     \n    +// Is tests whether rune is in the specified table of ranges.\n     func Is(ranges []Range, rune int) bool {\n     	// common case: rune is ASCII or Latin-1\n     	if rune < 0x100 {\n     		for i := 0; i < len(ranges); i++ {\n     			r := ranges[i];\n    -			if rune > r.hi {\n    +			if rune > r.Hi {\n     				continue;\n     			}\n    -			if rune < r.lo {\n    +			if rune < r.Lo {\n     				return false;\n     			}\n    -			return (rune - r.lo) % r.stride == 0;\n    +			return (rune - r.Lo) % r.Stride == 0;\n     		}\n     		return false;\n     	}\
    

    Is関数内のr.hi, r.lo, r.strideへの参照が、それぞれr.Hi, r.Lo, r.Strideに更新されました。同様に、二分探索を行う後半のロジックも更新されています。

    --- a/src/lib/unicode/letter.go
    +++ b/src/lib/unicode/letter.go
    @@ -547,10 +554,10 @@ func Is(ranges []Range, rune int) bool {\n     	for lo < hi {\n     		m := lo + (hi - lo)/2;\n     		r := ranges[m];\n    -		if r.lo <= rune && rune <= r.hi {\n    -			return (rune - r.lo) % r.stride == 0;\n    +		if r.Lo <= rune && rune <= r.Hi {\n    +			return (rune - r.Lo) % r.Stride == 0;\n     		}\n    -		if rune < r.lo {\n    +		if rune < r.Lo {\n     			hi = m;\n     		} else {\n     			lo = m+1;\
    

コアとなるコードの解説

Range構造体のフィールド名変更の意義

Go言語の可視性ルールにより、Range構造体のフィールド名がlo, hi, stride(小文字で始まる)からLo, Hi, Stride(大文字で始まる)に変更されたことは、非常に重要な意味を持ちます。

  • 変更前: フィールドが小文字で始まっていたため、これらのフィールドはunicodeパッケージ内部からしかアクセスできませんでした。つまり、unicodeパッケージを利用する外部のコードは、Range構造体のlo, hi, strideの値に直接アクセスしたり、設定したりすることができませんでした。
  • 変更後: フィールドが大文字で始まるようになったため、これらのフィールドはエクスポートされ、unicodeパッケージの外部からも直接アクセス可能になりました。これにより、開発者はRange構造体のインスタンスを作成し、そのLo, Hi, Strideフィールドに直接値を設定したり、既存のRangeインスタンスのこれらの値を読み取ったりすることができるようになります。これは、unicodeパッケージの柔軟性と再利用性を高める上で大きな改善です。例えば、カスタムのUnicode範囲を定義してIs関数に渡すようなシナリオが考えられます。

Is関数内の参照更新

Is関数は、与えられたルーンがrangesスライス内のいずれかのRangeに含まれるかを判定するロジックを実装しています。この関数は、Range構造体のlo, hi, strideフィールドにアクセスして、ルーンが範囲内にあるか、そしてstrideに従っているかをチェックします。

フィールド名がLo, Hi, Strideに変更されたことに伴い、Is関数内のこれらのフィールドへの参照もすべて更新されました。これは機能的な変更ではなく、APIの変更に合わせたコードの整合性を保つための修正です。これにより、Is関数は引き続き正しく動作し、エクスポートされたRangeフィールドを利用してUnicodeルーンのプロパティを効率的に判定できます。

このコミットは、Go言語の初期段階におけるUnicodeサポートの基盤を固め、将来的な拡張性と使いやすさを考慮した設計が行われていたことを示しています。特に、Go言語のシンプルで一貫した可視性ルールが、このようなAPIの改善にどのように貢献しているかがよくわかります。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメントおよびunicodeパッケージのソースコード
  • Go言語の可視性ルールに関する一般的な情報源(Go言語のチュートリアルやブログ記事など)
  • Unicodeに関する一般的な情報源(Wikipediaなど)