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

[インデックス 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は、特定の文字の範囲(Range16Range32)と、それらの範囲が属するカテゴリのプロパティを効率的に表現するためのデータ構造です。例えば、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に移動し、IsOneOfInを呼び出すように変更されています。これにより、コードの重複が避けられ、保守性が向上しています。

既存関数の更新

unicodeパッケージ内のIsGraphicIsPrint関数も、この新しい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関数と、それに伴う既存関数の変更です。

  1. 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関数のロジックと全く同じです。

  2. 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の移行を促すための重要な指示です。

  3. IsGraphicIsPrint関数の更新: これらの関数は、ルーンがグラフィック文字であるか、または印刷可能文字であるかを判定します。以前はIsOneOfを使用していましたが、新しいIn関数を使用するように変更されました。

    // 旧: return IsOneOf(GraphicRanges, r)
    // 新: return In(r, GraphicRanges...)
    

    ここでGraphicRanges...のように...演算子が使われているのは、GraphicRanges[]*RangeTable型のスライスであり、これをIn関数の可変長引数に展開して渡すためです。これにより、IsGraphicIsPrintの内部実装も、より新しい、推奨されるAPIを使用するようになりました。

  4. テストコードの更新: graphic_test.go内のテストコードも、IsOneOfの代わりにIn関数を使用するように更新されています。これは、新しいAPIが正しく機能することを確認し、また、テストコード自体も新しいAPIの使用例として機能するようにするためです。

これらの変更により、unicodeパッケージのAPIはより一貫性があり、使いやすくなりました。特に、複数のRangeTableに対するルーンの所属チェックが、より自然なGoのイディオムに沿った形で記述できるようになりました。

関連リンク

参考にした情報源リンク

  • 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は、特定の文字の範囲(Range16Range32)と、それらの範囲が属するカテゴリのプロパティを効率的に表現するためのデータ構造です。例えば、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に移動し、IsOneOfInを呼び出すように変更されています。これにより、コードの重複が避けられ、保守性が向上しています。

既存関数の更新

unicodeパッケージ内のIsGraphicIsPrint関数も、この新しい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関数と、それに伴う既存関数の変更です。

  1. 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関数のロジックと全く同じです。

  2. 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の移行を促すための重要な指示です。

  3. IsGraphicIsPrint関数の更新: これらの関数は、ルーンがグラフィック文字であるか、または印刷可能文字であるかを判定します。以前はIsOneOfを使用していましたが、新しいIn関数を使用するように変更されました。

    // 旧: return IsOneOf(GraphicRanges, r)
    // 新: return In(r, GraphicRanges...)
    

    ここでGraphicRanges...のように...演算子が使われているのは、GraphicRanges[]*RangeTable型のスライスであり、これをIn関数の可変長引数に展開して渡すためです。これにより、IsGraphicIsPrintの内部実装も、より新しい、推奨されるAPIを使用するようになりました。

  4. テストコードの更新: graphic_test.go内のテストコードも、IsOneOfの代わりにIn関数を使用するように更新されています。これは、新しいAPIが正しく機能することを確認し、また、テストコード自体も新しいAPIの使用例として機能するようにするためです。

これらの変更により、unicodeパッケージのAPIはより一貫性があり、使いやすくなりました。特に、複数のRangeTableに対するルーンの所属チェックが、より自然なGoのイディオムに沿った形で記述できるようになりました。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント
  • GitHubのgolang/goリポジトリのコミット履歴
  • Go言語のunicodeパッケージのソースコード
  • Effective Go
  • Web検索結果: "Go unicode RangeTable structure"