[インデックス 16855] ファイルの概要
このコミットは、Go言語のunicode
パッケージに新しい関数In
を追加し、既存のIsOneOf
関数の使いにくさを改善することを目的としています。In
関数は、指定されたルーン(Unicodeコードポイント)が、可変長引数で渡された複数のRangeTable
のいずれかに属するかどうかを判定します。これにより、IsOneOf
で必要だった[]*unicode.RangeTable
スライスを事前に構築する手間が省かれ、より直感的でGoの他のIs
関数群と一貫性のあるAPIが提供されます。
コミット
commit 6a801539c5f4702b1a7e9e7bbb117ddf889145c7
Author: Rob Pike <r@golang.org>
Date: Wed Jul 24 10:27:58 2013 +1000
unicode: add "In" function to test membership of a rune
The existing function, IsOneOf, is hard to use. Since the slice comes
before the rune, in parallelism with the other Is functions, the slice
is clumsy to build. This CL adds a nicer-signatured In function of
equivalent functionality (its implementation is identical) that's much
easier to use. Compare:
unicode.IsOneOf([]*unicode.RangeTable{unicode.Letter, unicode.Number}, r)
unicode.In(r, unicode.Letter, unicode.Number)
R=golang-dev, adg
CC=golang-dev
https://golang.org/cl/11672044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/6a801539c5f4702b1a7e9e7bbb117ddf889145c7
元コミット内容
このコミットは、Go言語のunicode
パッケージにIn
関数を追加します。既存のIsOneOf
関数は、ルーンの所属をテストするために[]*unicode.RangeTable
型のスライスを第一引数に取るため、使用が煩雑でした。新しいIn
関数は、ルーンを第一引数に、その後に可変長引数として*unicode.RangeTable
を取ることで、より自然な呼び出し方を提供します。機能的にはIsOneOf
と同一ですが、APIの使いやすさが大幅に向上しています。
例:
- 変更前:
unicode.IsOneOf([]*unicode.RangeTable{unicode.Letter, unicode.Number}, r)
- 変更後:
unicode.In(r, unicode.Letter, unicode.Number)
この変更は、unicode
パッケージ内のIsGraphic
およびIsPrint
関数も新しいIn
関数を使用するように更新しています。
変更の背景
Go言語のunicode
パッケージには、特定のルーンがUnicodeの特定のカテゴリ(例: 文字、数字、句読点など)に属するかどうかを判定するための様々なIs
関数(例: unicode.IsLetter
, unicode.IsDigit
)が提供されています。これらの関数は通常、ルーンを単一の引数として受け取ります。
しかし、複数のUnicodeカテゴリのいずれかにルーンが属するかどうかを判定したい場合、既存のIsOneOf
関数を使用する必要がありました。IsOneOf
のシグネチャはfunc IsOneOf(set []*RangeTable, r rune) bool
となっており、第一引数に*unicode.RangeTable
のスライスを渡す必要がありました。これは、複数のカテゴリをチェックするたびに、その場でスライスを構築しなければならないという点で、他のIs
関数群の直感的なAPIと比べて一貫性がなく、使いにくいという問題がありました。
このコミットは、このAPIの不便さを解消するために、よりGoらしい(idiomaticな)シグネチャを持つIn
関数を導入しました。これにより、ユーザーはスライスを明示的に構築することなく、可変長引数として複数のRangeTable
を直接渡せるようになり、コードの可読性と記述性が向上します。
前提知識の解説
1. ルーン (Rune)
Go言語において、rune
型はUnicodeのコードポイントを表す組み込み型です。これは実質的にint32
のエイリアスであり、UTF-8でエンコードされた文字列内の単一のUnicode文字を表現するために使用されます。Goの文字列はバイトのシーケンスであり、UTF-8でエンコードされているため、1つのルーンが1バイトから4バイトを占める可能性があります。unicode
パッケージは、これらのルーンに対する様々な操作を提供します。
2. Unicode RangeTable
unicode
パッケージでは、Unicodeの文字プロパティやカテゴリ(例: ひらがな、漢字、数字、句読点など)を定義するためにRangeTable
という構造体が使用されます。RangeTable
は、特定の文字の範囲(Range16
やRange32
)と、それらの範囲が属するカテゴリのプロパティを効率的に表現するためのデータ構造です。例えば、unicode.Letter
はすべてのUnicode文字(アルファベット)を含むRangeTable
であり、unicode.Number
はすべてのUnicode数字を含むRangeTable
です。
3. Goの可変長引数 (Variadic Functions)
Go言語では、関数の最後のパラメータに...
(三点リーダー)を付けることで、その関数が可変長引数を受け取れるようになります。これにより、関数は同じ型の0個以上の引数をスライスとして受け取ることができます。
例: func sum(nums ...int) int
この機能は、引数の数が事前に決まっていない場合に非常に便利であり、APIの柔軟性を高めます。
4. unicode.Is
関数
unicode
パッケージには、特定のRangeTable
に対してルーンが属するかどうかを判定するIs
関数があります。
func Is(rangeTab *RangeTable, r rune) bool
この関数は、RangeTable
とルーンを引数に取り、ルーンがそのRangeTable
に含まれていればtrue
を返します。IsOneOf
や新しいIn
関数は、内部的にこのIs
関数を利用して複数のRangeTable
に対するチェックを効率的に行います。
技術的詳細
このコミットの主要な技術的変更点は、Goの可変長引数機能を利用して、より使いやすいAPIを設計したことです。
IsOneOf
関数の問題点
既存のIsOneOf
関数は、以下のようなシグネチャでした。
func IsOneOf(set []*RangeTable, r rune) bool
この関数を呼び出す際には、常に[]*unicode.RangeTable
型のスライスを明示的に構築する必要がありました。例えば、ルーンr
が文字または数字であるかをチェックする場合、以下のように記述していました。
unicode.IsOneOf([]*unicode.RangeTable{unicode.Letter, unicode.Number}, r)
これは、特に複数のRangeTable
をチェックする場合に冗長であり、Goの他のIs
関数(例: unicode.IsLetter(r)
)のシンプルさと比較して、APIの一貫性を損なっていました。
In
関数の導入と可変長引数の活用
新しいIn
関数は、この問題を解決するために導入されました。そのシグネチャは以下の通りです。
func In(r rune, ranges ...*RangeTable) bool
ここで注目すべきは、ranges ...*RangeTable
という部分です。これは、In
関数が*unicode.RangeTable
型の引数を0個以上受け取ることができる可変長引数であることを示しています。関数内部では、これらの可変長引数は[]*unicode.RangeTable
型のスライスとして扱われます。
これにより、上記の例は以下のように簡潔に記述できるようになりました。
unicode.In(r, unicode.Letter, unicode.Number)
この形式は、ルーンを最初に指定し、その後にチェックしたいRangeTable
を列挙するという点で、他のIs
関数群(例: unicode.IsLetter(r)
)と引数の順序が揃い、より自然で直感的なAPIとなっています。
実装の効率性
コミットメッセージにもあるように、In
関数の実装はIsOneOf
と「同一」です。これは、In
関数が内部的に可変長引数で受け取ったranges
スライスをIsOneOf
関数に渡すか、あるいはIsOneOf
と同じロジック(ループで各RangeTable
に対してunicode.Is
を呼び出す)を直接実装していることを意味します。このコミットでは、IsOneOf
のロジックをIn
に移動し、IsOneOf
はIn
を呼び出すように変更されています。これにより、コードの重複が避けられ、保守性が向上しています。
既存関数の更新
unicode
パッケージ内のIsGraphic
とIsPrint
関数も、この新しいIn
関数を使用するように更新されました。これらの関数は、以前はIsOneOf
を使用していましたが、変更後は可変長引数展開(...
演算子)を用いてIn
関数にRangeTable
のスライスを渡すように修正されています。
例: return In(r, GraphicRanges...)
これは、既存のコードベースが新しい、より良いAPIを利用するように促す良い例であり、パッケージ全体のAPIの一貫性を高めます。
コアとなるコードの変更箇所
src/pkg/unicode/graphic.go
// 変更前
func IsGraphic(r rune) bool {
if uint32(r) <= MaxLatin1 {
return properties[uint8(r)]&pg != 0
}
return IsOneOf(GraphicRanges, r) // ここが変更
}
// 変更後
func IsGraphic(r rune) bool {
if uint32(r) <= MaxLatin1 {
return properties[uint8(r)]&pg != 0
}
return In(r, GraphicRanges...) // In関数を使用し、可変長引数展開
}
// 変更前
func IsPrint(r rune) bool {
if uint32(r) <= MaxLatin1 {
return properties[uint8(r)]&pp != 0
}
return IsOneOf(PrintRanges, r) // ここが変更
}
// 変更後
func IsPrint(r rune) bool {
if uint32(r) <= MaxLatin1 {
return properties[uint8(r)]&pp != 0
}
return In(r, PrintRanges...) // In関数を使用し、可変長引数展開
}
// 変更前 (IsOneOfの定義)
func IsOneOf(set []*RangeTable, r rune) bool {
for _, inside := range set {
if Is(inside, r) {
return true
}
}
return false
}
// 変更後 (IsOneOfの定義 - コメントと引数名が変更され、In関数が追加)
// The function "In" provides a nicer signature and should be used in preference to IsOneOf.
func IsOneOf(ranges []*RangeTable, r rune) bool { // 引数名がsetからrangesに変更
for _, inside := range ranges {
if Is(inside, r) {
return true
}
}
return false
}
// 新しく追加されたIn関数
func In(r rune, ranges ...*RangeTable) bool {
for _, inside := range ranges {
if Is(inside, r) {
return true
}
}
return false
}
src/pkg/unicode/graphic_test.go
// 変更前
func TestIsPrintLatin1(t *testing.T) {
for i := rune(0); i <= MaxLatin1; i++ {
got := IsPrint(i)
want := IsOneOf(PrintRanges, i) // ここが変更
if i == ' ' {
want = true
}
if got != want {
t.Errorf("%U incorrect: got %t; want %t", i, got, want)
}
}
}
// 変更後
func TestIsPrintLatin1(t *testing.T) {
for i := rune(0); i <= MaxLatin1; i++ {
got := IsPrint(i)
want := In(i, PrintRanges...) // In関数を使用
if i == ' ' {
want = true
}
if got != want {
t.Errorf("%U incorrect: got %t; want %t", i, got, want)
}
}
}
// 変更前
func TestIsGraphicLatin1(t *testing.T) {
for i := rune(0); i <= MaxLatin1; i++ {
got := IsGraphic(i)
want := IsOneOf(GraphicRanges, i) // ここが変更
if got != want {
t.Errorf("%U incorrect: got %t; want %t", i, got, want)
}
}
}
// 変更後
func TestIsGraphicLatin1(t *testing.T) {
for i := rune(0); i <= MaxLatin1; i++ {
got := IsGraphic(i)
want := In(i, GraphicRanges...) // In関数を使用
if got != want {
t.Errorf("%U incorrect: got %t; want %t", i, got, want)
}
}
}
コアとなるコードの解説
このコミットの核心は、unicode/graphic.go
に追加されたIn
関数と、それに伴う既存関数の変更です。
-
In
関数の追加:func In(r rune, ranges ...*RangeTable) bool { for _, inside := range ranges { if Is(inside, r) { return true } } return false }
この関数は、ルーン
r
と、可変長引数ranges
として渡された*RangeTable
のスライスを受け取ります。内部では、ranges
スライスをループし、それぞれのRangeTable
に対してunicode.Is(inside, r)
を呼び出します。もしルーンr
がどれか一つのRangeTable
にでも含まれていれば、即座にtrue
を返します。全てのRangeTable
をチェックしても含まれていなければfalse
を返します。この実装は、以前のIsOneOf
関数のロジックと全く同じです。 -
IsOneOf
関数の変更:IsOneOf
関数の実装自体は変更されていませんが、そのシグネチャの引数名がset
からranges
に変更され、コメントが追加されました。// The function "In" provides a nicer signature and should be used in preference to IsOneOf. func IsOneOf(ranges []*RangeTable, r rune) bool { // ... (In関数と同一のロジック) }
このコメントは、新しい
In
関数がより良いシグネチャを提供し、今後はIsOneOf
よりもIn
を使用すべきであることを明示しています。これは、APIの移行を促すための重要な指示です。 -
IsGraphic
とIsPrint
関数の更新: これらの関数は、ルーンがグラフィック文字であるか、または印刷可能文字であるかを判定します。以前はIsOneOf
を使用していましたが、新しいIn
関数を使用するように変更されました。// 旧: return IsOneOf(GraphicRanges, r) // 新: return In(r, GraphicRanges...)
ここで
GraphicRanges...
のように...
演算子が使われているのは、GraphicRanges
が[]*RangeTable
型のスライスであり、これをIn
関数の可変長引数に展開して渡すためです。これにより、IsGraphic
やIsPrint
の内部実装も、より新しい、推奨されるAPIを使用するようになりました。 -
テストコードの更新:
graphic_test.go
内のテストコードも、IsOneOf
の代わりにIn
関数を使用するように更新されています。これは、新しいAPIが正しく機能することを確認し、また、テストコード自体も新しいAPIの使用例として機能するようにするためです。
これらの変更により、unicode
パッケージのAPIはより一貫性があり、使いやすくなりました。特に、複数のRangeTable
に対するルーンの所属チェックが、より自然なGoのイディオムに沿った形で記述できるようになりました。
関連リンク
- Go言語の
unicode
パッケージのドキュメント: https://pkg.go.dev/unicode - Go言語の可変長引数に関する公式ドキュメント(Effective Goより): https://go.dev/doc/effective_go#variadic
- Go言語の
rune
に関する公式ドキュメント: https://go.dev/blog/strings
参考にした情報源リンク
- Go言語の公式ドキュメント
- GitHubのgolang/goリポジトリのコミット履歴
- Go言語の
unicode
パッケージのソースコード - Effective Go
[インデックス 16855] ファイルの概要
このコミットは、Go言語のunicode
パッケージに新しい関数In
を追加し、既存のIsOneOf
関数の使いにくさを改善することを目的としています。In
関数は、指定されたルーン(Unicodeコードポイント)が、可変長引数で渡された複数のRangeTable
のいずれかに属するかどうかを判定します。これにより、IsOneOf
で必要だった[]*unicode.RangeTable
スライスを事前に構築する手間が省かれ、より直感的でGoの他のIs
関数群と一貫性のあるAPIが提供されます。
コミット
commit 6a801539c5f4702b1a7e9e7bbb117ddf889145c7
Author: Rob Pike <r@golang.org>
Date: Wed Jul 24 10:27:58 2013 +1000
unicode: add "In" function to test membership of a rune
The existing function, IsOneOf, is hard to use. Since the slice comes
before the rune, in parallelism with the other Is functions, the slice
is clumsy to build. This CL adds a nicer-signatured In function of
equivalent functionality (its implementation is identical) that's much
easier to use. Compare:
unicode.IsOneOf([]*unicode.RangeTable{unicode.Letter, unicode.Number}, r)
unicode.In(r, unicode.Letter, unicode.Number)
R=golang-dev, adg
CC=golang-dev
https://golang.org/cl/11672044
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/6a801539c5f4702b1a7e9e7bbb117ddf889145c7
元コミット内容
このコミットは、Go言語のunicode
パッケージにIn
関数を追加します。既存のIsOneOf
関数は、ルーンの所属をテストするために[]*unicode.RangeTable
型のスライスを第一引数に取るため、使用が煩雑でした。新しいIn
関数は、ルーンを第一引数に、その後に可変長引数として*unicode.RangeTable
を取ることで、より自然な呼び出し方を提供します。機能的にはIsOneOf
と同一ですが、APIの使いやすさが大幅に向上しています。
例:
- 変更前:
unicode.IsOneOf([]*unicode.RangeTable{unicode.Letter, unicode.Number}, r)
- 変更後:
unicode.In(r, unicode.Letter, unicode.Number)
この変更は、unicode
パッケージ内のIsGraphic
およびIsPrint
関数も新しいIn
関数を使用するように更新しています。
変更の背景
Go言語のunicode
パッケージには、特定のルーンがUnicodeの特定のカテゴリ(例: 文字、数字、句読点など)に属するかどうかを判定するための様々なIs
関数(例: unicode.IsLetter
, unicode.IsDigit
)が提供されています。これらの関数は通常、ルーンを単一の引数として受け取ります。
しかし、複数のUnicodeカテゴリのいずれかにルーンが属するかどうかを判定したい場合、既存のIsOneOf
関数を使用する必要がありました。IsOneOf
のシグネチャはfunc IsOneOf(set []*RangeTable, r rune) bool
となっており、第一引数に*unicode.RangeTable
のスライスを渡す必要がありました。これは、複数のカテゴリをチェックするたびに、その場でスライスを構築しなければならないという点で、他のIs
関数群の直感的なAPIと比べて一貫性がなく、使いにくいという問題がありました。
このコミットは、このAPIの不便さを解消するために、よりGoらしい(idiomaticな)シグネチャを持つIn
関数を導入しました。これにより、ユーザーはスライスを明示的に構築することなく、可変長引数として複数のRangeTable
を直接渡せるようになり、コードの可読性と記述性が向上します。
前提知識の解説
1. ルーン (Rune)
Go言語において、rune
型はUnicodeのコードポイントを表す組み込み型です。これは実質的にint32
のエイリアスであり、UTF-8でエンコードされた文字列内の単一のUnicode文字を表現するために使用されます。Goの文字列はバイトのシーケンスであり、UTF-8でエンコードされているため、1つのルーンが1バイトから4バイトを占める可能性があります。unicode
パッケージは、これらのルーンに対する様々な操作を提供します。
2. Unicode RangeTable
unicode
パッケージでは、Unicodeの文字プロパティやカテゴリ(例: ひらがな、漢字、数字、句読点など)を定義するためにRangeTable
という構造体が使用されます。RangeTable
は、特定の文字の範囲(Range16
やRange32
)と、それらの範囲が属するカテゴリのプロパティを効率的に表現するためのデータ構造です。例えば、unicode.Letter
はすべてのUnicode文字(アルファベット)を含むRangeTable
であり、unicode.Number
はすべてのUnicode数字を含むRangeTable
です。
RangeTable
は、Unicodeコードポイントの集合を定義するために使用され、その内部ではコードポイントの範囲を効率的に表現するために、ソートされ重複のないR16
(16ビットコードポイント用)とR32
(32ビットコードポイント用)という2つのスライスに範囲を格納します。これにより、特に広範囲の文字セットにおいて、個々のコードポイントではなく範囲を格納することで、スペース効率が向上します。
3. Goの可変長引数 (Variadic Functions)
Go言語では、関数の最後のパラメータに...
(三点リーダー)を付けることで、その関数が可変長引数を受け取れるようになります。これにより、関数は同じ型の0個以上の引数をスライスとして受け取ることができます。
例: func sum(nums ...int) int
この機能は、引数の数が事前に決まっていない場合に非常に便利であり、APIの柔軟性を高めます。
4. unicode.Is
関数
unicode
パッケージには、特定のRangeTable
に対してルーンが属するかどうかを判定するIs
関数があります。
func Is(rangeTab *RangeTable, r rune) bool
この関数は、RangeTable
とルーンを引数に取り、ルーンがそのRangeTable
に含まれていればtrue
を返します。IsOneOf
や新しいIn
関数は、内部的にこのIs
関数を利用して複数のRangeTable
に対するチェックを効率的に行います。
技術的詳細
このコミットの主要な技術的変更点は、Goの可変長引数機能を利用して、より使いやすいAPIを設計したことです。
IsOneOf
関数の問題点
既存のIsOneOf
関数は、以下のようなシグネチャでした。
func IsOneOf(set []*RangeTable, r rune) bool
この関数を呼び出す際には、常に[]*unicode.RangeTable
型のスライスを明示的に構築する必要がありました。例えば、ルーンr
が文字または数字であるかをチェックする場合、以下のように記述していました。
unicode.IsOneOf([]*unicode.RangeTable{unicode.Letter, unicode.Number}, r)
これは、特に複数のRangeTable
をチェックする場合に冗長であり、Goの他のIs
関数(例: unicode.IsLetter
, unicode.IsDigit
)のシンプルさと比較して、APIの一貫性を損なっていました。
In
関数の導入と可変長引数の活用
新しいIn
関数は、この問題を解決するために導入されました。そのシグネチャは以下の通りです。
func In(r rune, ranges ...*RangeTable) bool
ここで注目すべきは、ranges ...*RangeTable
という部分です。これは、In
関数が*unicode.RangeTable
型の引数を0個以上受け取ることができる可変長引数であることを示しています。関数内部では、これらの可変長引数は[]*unicode.RangeTable
型のスライスとして扱われます。
これにより、上記の例は以下のように簡潔に記述できるようになりました。
unicode.In(r, unicode.Letter, unicode.Number)
この形式は、ルーンを最初に指定し、その後にチェックしたいRangeTable
を列挙するという点で、他のIs
関数群(例: unicode.IsLetter(r)
)と引数の順序が揃い、より自然で直感的なAPIとなっています。
実装の効率性
コミットメッセージにもあるように、In
関数の実装はIsOneOf
と「同一」です。これは、In
関数が内部的に可変長引数で受け取ったranges
スライスをIsOneOf
関数に渡すか、あるいはIsOneOf
と同じロジック(ループで各RangeTable
に対してunicode.Is
を呼び出す)を直接実装していることを意味します。このコミットでは、IsOneOf
のロジックをIn
に移動し、IsOneOf
はIn
を呼び出すように変更されています。これにより、コードの重複が避けられ、保守性が向上しています。
既存関数の更新
unicode
パッケージ内のIsGraphic
とIsPrint
関数も、この新しいIn
関数を使用するように更新されました。これらの関数は、以前はIsOneOf
を使用していましたが、変更後は可変長引数展開(...
演算子)を用いてIn
関数にRangeTable
のスライスを渡すように修正されています。
例: return In(r, GraphicRanges...)
これは、既存のコードベースが新しい、より良いAPIを利用するように促す良い例であり、パッケージ全体のAPIの一貫性を高めます。
コアとなるコードの変更箇所
src/pkg/unicode/graphic.go
// 変更前
func IsGraphic(r rune) bool {
if uint32(r) <= MaxLatin1 {
return properties[uint8(r)]&pg != 0
}
return IsOneOf(GraphicRanges, r) // ここが変更
}
// 変更後
func IsGraphic(r rune) bool {
if uint32(r) <= MaxLatin1 {
return properties[uint8(r)]&pg != 0
}
return In(r, GraphicRanges...) // In関数を使用し、可変長引数展開
}
// 変更前
func IsPrint(r rune) bool {
if uint32(r) <= MaxLatin1 {
return properties[uint8(r)]&pp != 0
}
return IsOneOf(PrintRanges, r) // ここが変更
}
// 変更後
func IsPrint(r rune) bool {
if uint32(r) <= MaxLatin1 {
return properties[uint8(r)]&pp != 0
}
return In(r, PrintRanges...) // In関数を使用し、可変長引数展開
}
// 変更前 (IsOneOfの定義)
func IsOneOf(set []*RangeTable, r rune) bool {
for _, inside := range set {
if Is(inside, r) {
return true
}
}
return false
}
// 変更後 (IsOneOfの定義 - コメントと引数名が変更され、In関数が追加)
// The function "In" provides a nicer signature and should be used in preference to IsOneOf.
func IsOneOf(ranges []*RangeTable, r rune) bool { // 引数名がsetからrangesに変更
for _, inside := range ranges {
if Is(inside, r) {
return true
}
}
return false
}
// 新しく追加されたIn関数
func In(r rune, ranges ...*RangeTable) bool {
for _, inside := range ranges {
if Is(inside, r) {
return true
}
}
return false
}
src/pkg/unicode/graphic_test.go
// 変更前
func TestIsPrintLatin1(t *testing.T) {
for i := rune(0); i <= MaxLatin1; i++ {
got := IsPrint(i)
want := IsOneOf(PrintRanges, i) // ここが変更
if i == ' ' {
want = true
}
if got != want {
t.Errorf("%U incorrect: got %t; want %t", i, got, want)
}
}
}
// 変更後
func TestIsPrintLatin1(t *testing.T) {
for i := rune(0); i <= MaxLatin1; i++ {
got := IsPrint(i)
want := In(i, PrintRanges...) // In関数を使用
if i == ' ' {
want = true
}
if got != want {
t.Errorf("%U incorrect: got %t; want %t", i, got, want)
}
}
}
// 変更前
func TestIsGraphicLatin1(t *testing.T) {
for i := rune(0); i <= MaxLatin1; i++ {
got := IsGraphic(i)
want := IsOneOf(GraphicRanges, i) // ここが変更
if got != want {
t.Errorf("%U incorrect: got %t; want %t", i, got, want)
}
}
}
// 変更後
func TestIsGraphicLatin1(t *testing.T) {
for i := rune(0); i <= MaxLatin1; i++ {
got := IsGraphic(i)
want := In(i, GraphicRanges...) // In関数を使用
if got != want {
t.Errorf("%U incorrect: got %t; want %t", i, got, want)
}
}
}
コアとなるコードの解説
このコミットの核心は、unicode/graphic.go
に追加されたIn
関数と、それに伴う既存関数の変更です。
-
In
関数の追加:func In(r rune, ranges ...*RangeTable) bool { for _, inside := range ranges { if Is(inside, r) { return true } } return false }
この関数は、ルーン
r
と、可変長引数ranges
として渡された*RangeTable
のスライスを受け取ります。内部では、ranges
スライスをループし、それぞれのRangeTable
に対してunicode.Is(inside, r)
を呼び出します。もしルーンr
がどれか一つのRangeTable
にでも含まれていれば、即座にtrue
を返します。全てのRangeTable
をチェックしても含まれていなければfalse
を返します。この実装は、以前のIsOneOf
関数のロジックと全く同じです。 -
IsOneOf
関数の変更:IsOneOf
関数の実装自体は変更されていませんが、そのシグネチャの引数名がset
からranges
に変更され、コメントが追加されました。// The function "In" provides a nicer signature and should be used in preference to IsOneOf. func IsOneOf(ranges []*RangeTable, r rune) bool { // ... (In関数と同一のロジック) }
このコメントは、新しい
In
関数がより良いシグネチャを提供し、今後はIsOneOf
よりもIn
を使用すべきであることを明示しています。これは、APIの移行を促すための重要な指示です。 -
IsGraphic
とIsPrint
関数の更新: これらの関数は、ルーンがグラフィック文字であるか、または印刷可能文字であるかを判定します。以前はIsOneOf
を使用していましたが、新しいIn
関数を使用するように変更されました。// 旧: return IsOneOf(GraphicRanges, r) // 新: return In(r, GraphicRanges...)
ここで
GraphicRanges...
のように...
演算子が使われているのは、GraphicRanges
が[]*RangeTable
型のスライスであり、これをIn
関数の可変長引数に展開して渡すためです。これにより、IsGraphic
やIsPrint
の内部実装も、より新しい、推奨されるAPIを使用するようになりました。 -
テストコードの更新:
graphic_test.go
内のテストコードも、IsOneOf
の代わりにIn
関数を使用するように更新されています。これは、新しいAPIが正しく機能することを確認し、また、テストコード自体も新しいAPIの使用例として機能するようにするためです。
これらの変更により、unicode
パッケージのAPIはより一貫性があり、使いやすくなりました。特に、複数のRangeTable
に対するルーンの所属チェックが、より自然なGoのイディオムに沿った形で記述できるようになりました。
関連リンク
- Go言語の
unicode
パッケージのドキュメント: https://pkg.go.dev/unicode - Go言語の可変長引数に関する公式ドキュメント(Effective Goより): https://go.dev/doc/effective_go#variadic
- Go言語の
rune
に関する公式ドキュメント: https://go.dev/blog/strings
参考にした情報源リンク
- Go言語の公式ドキュメント
- GitHubのgolang/goリポジトリのコミット履歴
- Go言語の
unicode
パッケージのソースコード - Effective Go
- Web検索結果: "Go unicode RangeTable structure"