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

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

このコミットは、Go言語の実験的な正規化パッケージ exp/norm 内のテストファイル normregtest.go における型定義の修正に関するものです。具体的には、int 型として扱われていた文字(rune)関連の変数を、Go言語でUnicodeコードポイントを表すための適切な rune 型に修正しています。これにより、テストの正確性と意図が明確化され、潜在的なバグが回避されます。

コミット

commit 7e797be7a3607c294285c8eaa47aed818b76acde
Author: Joel Sing <jsing@google.com>
Date:   Sun Dec 11 09:25:09 2011 -0800

    exp/norm: fix rune/int types in test

    R=golang-dev, r
    CC=golang-dev
    https://golang.org/cl/5472067

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

https://github.com/golang/go/commit/7e797be7a3607c294285c8eaa47aed818b76acde

元コミット内容

exp/norm: fix rune/int types in test

このコミットは、src/pkg/exp/norm/normregtest.go ファイル内のテストコードにおいて、rune 型として扱うべき変数が誤って int 型として宣言または使用されていた箇所を修正しています。

変更の背景

Go言語において、rune 型はUnicodeのコードポイントを表すために特別に設計された int32 のエイリアスです。一方、int 型はプラットフォームに依存する整数型であり、通常は32ビットまたは64ビットの符号付き整数です。文字やUnicodeコードポイントを扱う際には、その意味論的な正確性を保つために rune 型を使用することが推奨されます。

exp/norm パッケージは、Unicode正規化フォーム(NFC, NFD, NFKC, NFKDなど)を扱うための実験的なパッケージです。このようなパッケージのテストコードでは、個々の文字(rune)を正確に表現し、操作することが極めて重要です。

このコミットが行われた2011年12月は、Go言語がまだ比較的新しく、標準ライブラリや慣習が進化している時期でした。初期のコードベースでは、runeint の使い分けに関する理解がまだ完全に浸透していなかったり、一部で混同があったりする可能性がありました。このコミットは、テストコードの正確性を向上させ、Go言語の型システムにおける rune の適切な使用法に準拠させることを目的としています。

具体的には、テストデータから読み込んだ文字コードや、文字単位のテスト処理で使用される変数が int 型として扱われていたため、これが rune 型の本来の意図と合致しない可能性がありました。この修正により、テストコードがより堅牢になり、Unicode文字の正確な処理を保証できるようになります。

前提知識の解説

Go言語の rune 型と int

  • int: Go言語の int 型は、プラットフォームに依存する符号付き整数型です。通常、32ビットシステムでは32ビット、64ビットシステムでは64ビットの幅を持ちます。一般的な数値計算に使用されます。
  • rune: Go言語における rune 型は、int32 のエイリアスです。これはUnicodeのコードポイント(文字)を表すために特別に導入されました。Go言語の文字列はUTF-8でエンコードされたバイトのシーケンスですが、個々のUnicode文字を操作する際には rune 型が用いられます。例えば、for range ループで文字列をイテレートすると、各要素は rune 型として取得されます。

Unicode正規化 (Unicode Normalization Forms)

Unicode正規化とは、同じ文字を表す異なるUnicodeシーケンスを、一貫した(正規化された)表現に変換するプロセスです。これは、テキストの比較、検索、ソートなどの操作において、異なる表現を持つ同じ文字が正しく扱われるようにするために重要です。

主な正規化フォームには以下のものがあります。

  • NFC (Normalization Form C): 合成済み文字(Precomposed characters)を優先します。例えば、「é」は単一のコードポイントで表現されます。
  • NFD (Normalization Form D): 分解済み文字(Decomposed characters)を優先します。例えば、「é」は「e」と結合用アクサン記号の2つのコードポイントで表現されます。
  • NFKC (Normalization Form KC): 互換性分解(Compatibility Decomposition)と正規合成(Canonical Composition)を適用します。見た目が似ているが意味が異なる文字(例: 全角数字と半角数字)を統一します。
  • NFKD (Normalization Form KD): 互換性分解のみを適用します。

exp/norm パッケージは、これらの正規化フォームをGo言語で実装するための実験的な試みでした。

utf8.EncodeRune

utf8.EncodeRune はGo言語の unicode/utf8 パッケージに含まれる関数です。この関数は、与えられた rune をUTF-8エンコーディングでバイトスライスに変換し、そのバイト数を返します。これは、rune 型のUnicodeコードポイントを、Go言語の文字列が内部的に使用するUTF-8バイトシーケンスに変換する際に使用されます。

技術的詳細

このコミットは、src/pkg/exp/norm/normregtest.go ファイル内の3箇所で型を int から rune に変更しています。

  1. loadTestData() 関数内:

    --- a/src/pkg/exp/norm/normregtest.go
    +++ b/src/pkg/exp/norm/normregtest.go
    @@ -177,7 +177,7 @@ func loadTestData() {
     				}
     			if test.r == 0 {
     				// save for CharacterByCharacterTests
    -				test.r = int(r)
    +				test.r = rune(r)
     			}
     			var buf [utf8.UTFMax]byte
     			sz := utf8.EncodeRune(buf[:], rune(r))
    

    test.r は、テストデータから読み込まれた文字のコードポイントを保存するためのフィールドです。元のコードでは int(r) と型変換して代入していましたが、r 自体が rune 型であるか、あるいは rune として扱うべき値であるため、rune(r) に修正することで、test.r がUnicodeコードポイントを正確に保持するようにしています。これにより、test.r の意味論が明確になり、将来的な誤解やバグを防ぎます。

  2. CharacterByCharacterTests() 関数内:

    --- a/src/pkg/exp/norm/normregtest.go
    +++ b/src/pkg/exp/norm/normregtest.go
    @@ -242,9 +242,9 @@ func doConformanceTests(t *Test, partn int) {
    
     func CharacterByCharacterTests() {
     	tests := part[1].tests
    -	last := 0
    +	var last rune = 0
     	for i := 0; i <= len(tests); i++ { // last one is special case
    -		var r int
    +		var r rune
     		if i == len(tests) {
     			r = 0x2FA1E // Don't have to go to 0x10FFFF
     		} else {
    

    CharacterByCharacterTests() 関数は、文字単位で正規化テストを行うためのものです。

    • last := 0var last rune = 0 に変更されています。last 変数は、前の文字のコードポイントを保持するために使用されると推測されます。文字コードポイントを保持するためには rune 型が適切です。初期値 0 はUnicodeのU+0000 NULL文字を表すため、rune 型で初期化しても問題ありません。
    • var r intvar r rune に変更されています。r 変数は、現在のテスト対象の文字コードポイントを保持するために使用されます。これも同様に、文字コードポイントを扱うため rune 型が適切です。

これらの変更は、Go言語の型システムにおける rune の役割を正しく反映し、Unicode文字のテストが意図通りに行われることを保証します。int 型を使用した場合でも、多くの場合 rune の値(int32 の範囲)は int に収まるため、コンパイルエラーにはならない可能性があります。しかし、意味論的な正確性を欠き、コードの意図を不明瞭にするだけでなく、将来的に int のサイズが変更された場合や、より大きなUnicodeコードポイントが導入された場合に問題を引き起こす可能性がありました。

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

src/pkg/exp/norm/normregtest.go

--- a/src/pkg/exp/norm/normregtest.go
+++ b/src/pkg/exp/norm/normregtest.go
@@ -177,7 +177,7 @@ func loadTestData() {
 				}
 			if test.r == 0 {
 				// save for CharacterByCharacterTests
-				test.r = int(r)
+				test.r = rune(r)
 			}
 			var buf [utf8.UTFMax]byte
 			sz := utf8.EncodeRune(buf[:], rune(r))
@@ -242,9 +242,9 @@ func doConformanceTests(t *Test, partn int) {

 func CharacterByCharacterTests() {
 	tests := part[1].tests
-	last := 0
+	var last rune = 0
 	for i := 0; i <= len(tests); i++ { // last one is special case
-		var r int
+		var r rune
 		if i == len(tests) {
 			r = 0x2FA1E // Don't have to go to 0x10FFFF
 		} else {

コアとなるコードの解説

このコミットの核心は、int 型で宣言されていた変数を rune 型に修正することです。

  1. test.r = rune(r): loadTestData() 関数は、おそらく外部のテストデータファイルからUnicodeコードポイントを読み込んでいます。r は読み込まれたコードポイントを表す変数であり、test.r はそのコードポイントを構造体 test のフィールドに保存するためのものです。元のコードでは int(r)int 型にキャストしていましたが、rune 型として扱うべき値を rune 型として保存することで、データの意味論的な整合性を保ちます。

  2. var last rune = 0: CharacterByCharacterTests() 関数は、文字単位でテストを行う際に、前の文字のコードポイントを last 変数に保持していると考えられます。文字コードポイントは rune 型で表現するのが適切であるため、int から rune に変更されました。初期値 0 はUnicodeのNULL文字(U+0000)を表し、rune 型として有効です。

  3. var r rune: 同じく CharacterByCharacterTests() 関数内で、現在のテスト対象の文字コードポイントを保持する r 変数も int から rune に変更されました。これにより、r が常にUnicodeコードポイントとして正しく解釈され、utf8.EncodeRune などの関数に渡される際にも型の一貫性が保たれます。

これらの変更は、Go言語の rune 型の導入意図に沿ったものであり、Unicode文字を扱うコードの正確性、可読性、および保守性を向上させます。特に、Unicode正規化のような文字の厳密な処理が求められる文脈では、適切な型を使用することが非常に重要です。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント
  • Unicode Consortiumの公式ウェブサイト
  • Go言語のソースコードリポジトリ (特に src/pkg/exp/norm ディレクトリ)
  • Go言語に関する技術ブログやフォーラムでの議論 (当時の情報を含む)
  • コミットメッセージに記載されている Go Gerrit の変更リスト (CL): https://golang.org/cl/5472067 (現在は https://go.dev/cl/5472067 にリダイレクトされる可能性が高い)
    • このCLページで、より詳細な議論や背景情報が提供されている可能性があります。# [インデックス 10701] ファイルの概要

このコミットは、Go言語の実験的な正規化パッケージ exp/norm 内のテストファイル normregtest.go における型定義の修正に関するものです。具体的には、int 型として扱われていた文字(rune)関連の変数を、Go言語でUnicodeコードポイントを表すための適切な rune 型に修正しています。これにより、テストの正確性と意図が明確化され、潜在的なバグが回避されます。

コミット

commit 7e797be7a3607c294285c8eaa47aed818b76acde
Author: Joel Sing <jsing@google.com>
Date:   Sun Dec 11 09:25:09 2011 -0800

    exp/norm: fix rune/int types in test

    R=golang-dev, r
    CC=golang-dev
    https://golang.org/cl/5472067

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

https://github.com/golang/go/commit/7e797be7a3607c294285c8eaa47aed818b76acde

元コミット内容

exp/norm: fix rune/int types in test

このコミットは、src/pkg/exp/norm/normregtest.go ファイル内のテストコードにおいて、rune 型として扱うべき変数が誤って int 型として宣言または使用されていた箇所を修正しています。

変更の背景

Go言語において、rune 型はUnicodeのコードポイントを表すために特別に設計された int32 のエイリアスです。一方、int 型はプラットフォームに依存する整数型であり、通常は32ビットまたは64ビットの符号付き整数です。文字やUnicodeコードポイントを扱う際には、その意味論的な正確性を保つために rune 型を使用することが推奨されます。

exp/norm パッケージは、Unicode正規化フォーム(NFC, NFD, NFKC, NFKDなど)を扱うための実験的なパッケージです。このようなパッケージのテストコードでは、個々の文字(rune)を正確に表現し、操作することが極めて重要です。

このコミットが行われた2011年12月は、Go言語がまだ比較的新しく、標準ライブラリや慣習が進化している時期でした。初期のコードベースでは、runeint の使い分けに関する理解がまだ完全に浸透していなかったり、一部で混同があったりする可能性がありました。このコミットは、テストコードの正確性を向上させ、Go言語の型システムにおける rune の適切な使用法に準拠させることを目的としています。

具体的には、テストデータから読み込んだ文字コードや、文字単位のテスト処理で使用される変数が int 型として扱われていたため、これが rune 型の本来の意図と合致しない可能性がありました。この修正により、テストコードがより堅牢になり、Unicode文字の正確な処理を保証できるようになります。

前提知識の解説

Go言語の rune 型と int

  • int: Go言語の int 型は、プラットフォームに依存する符号付き整数型です。通常、32ビットシステムでは32ビット、64ビットシステムでは64ビットの幅を持ちます。一般的な数値計算に使用されます。
  • rune: Go言語における rune 型は、int32 のエイリアスです。これはUnicodeのコードポイント(文字)を表すために特別に導入されました。Go言語の文字列はUTF-8でエンコードされたバイトのシーケンスですが、個々のUnicode文字を操作する際には rune 型が用いられます。例えば、for range ループで文字列をイテレートすると、各要素は rune 型として取得されます。

Unicode正規化 (Unicode Normalization Forms)

Unicode正規化とは、同じ文字を表す異なるUnicodeシーケンスを、一貫した(正規化された)表現に変換するプロセスです。これは、テキストの比較、検索、ソートなどの操作において、異なる表現を持つ同じ文字が正しく扱われるようにするために重要です。

主な正規化フォームには以下のものがあります。

  • NFC (Normalization Form C): 合成済み文字(Precomposed characters)を優先します。例えば、「é」は単一のコードポイントで表現されます。
  • NFD (Normalization Form D): 分解済み文字(Decomposed characters)を優先します。例えば、「é」は「e」と結合用アクサン記号の2つのコードポイントで表現されます。
  • NFKC (Normalization Form KC): 互換性分解(Compatibility Decomposition)と正規合成(Canonical Composition)を適用します。見た目が似ているが意味が異なる文字(例: 全角数字と半角数字)を統一します。
  • NFKD (Normalization Form KD): 互換性分解のみを適用します。

exp/norm パッケージは、これらの正規化フォームをGo言語で実装するための実験的な試みでした。

utf8.EncodeRune

utf8.EncodeRune はGo言語の unicode/utf8 パッケージに含まれる関数です。この関数は、与えられた rune をUTF-8エンコーディングでバイトスライスに変換し、そのバイト数を返します。これは、rune 型のUnicodeコードポイントを、Go言語の文字列が内部的に使用するUTF-8バイトシーケンスに変換する際に使用されます。

技術的詳細

このコミットは、src/pkg/exp/norm/normregtest.go ファイル内の3箇所で型を int から rune に変更しています。

  1. loadTestData() 関数内:

    --- a/src/pkg/exp/norm/normregtest.go
    +++ b/src/pkg/exp/norm/normregtest.go
    @@ -177,7 +177,7 @@ func loadTestData() {
     				}
     			if test.r == 0 {
     				// save for CharacterByCharacterTests
    -				test.r = int(r)
    +				test.r = rune(r)
     			}
     			var buf [utf8.UTFMax]byte
     			sz := utf8.EncodeRune(buf[:], rune(r))
    

    test.r は、テストデータから読み込まれた文字のコードポイントを保存するためのフィールドです。元のコードでは int(r) と型変換して代入していましたが、r 自体が rune 型であるか、あるいは rune として扱うべき値であるため、rune(r) に修正することで、test.r がUnicodeコードポイントを正確に保持するようにしています。これにより、test.r の意味論が明確になり、将来的な誤解やバグを防ぎます。

  2. CharacterByCharacterTests() 関数内:

    --- a/src/pkg/exp/norm/normregtest.go
    +++ b/src/pkg/exp/norm/normregtest.go
    @@ -242,9 +242,9 @@ func doConformanceTests(t *Test, partn int) {
    
     func CharacterByCharacterTests() {
     	tests := part[1].tests
    
  • last := 0
  • var last rune = 0 for i := 0; i <= len(tests); i++ { // last one is special case
  •   var r int
    
  •   var r rune
      	if i == len(tests) {
      		r = 0x2FA1E // Don't have to go to 0x10FFFF
      	} else {
    
    `CharacterByCharacterTests()` 関数は、文字単位で正規化テストを行うためのものです。
    *   `last := 0` が `var last rune = 0` に変更されています。`last` 変数は、前の文字のコードポイントを保持するために使用されると推測されます。文字コードポイントを保持するためには `rune` 型が適切です。初期値 `0` はUnicodeのU+0000 NULL文字を表すため、`rune` 型で初期化しても問題ありません。
    *   `var r int` が `var r rune` に変更されています。`r` 変数は、現在のテスト対象の文字コードポイントを保持するために使用されます。これも同様に、文字コードポイントを扱うため `rune` 型が適切です。
    
    

これらの変更は、Go言語の型システムにおける rune の役割を正しく反映し、Unicode文字のテストが意図通りに行われることを保証します。int 型を使用した場合でも、多くの場合 rune の値(int32 の範囲)は int に収まるため、コンパイルエラーにはならない可能性があります。しかし、意味論的な正確性を欠き、コードの意図を不明瞭にするだけでなく、将来的に int のサイズが変更された場合や、より大きなUnicodeコードポイントが導入された場合に問題を引き起こす可能性がありました。

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

src/pkg/exp/norm/normregtest.go

--- a/src/pkg/exp/norm/normregtest.go
+++ b/src/pkg/exp/norm/normregtest.go
@@ -177,7 +177,7 @@ func loadTestData() {
 				}
 			if test.r == 0 {
 				// save for CharacterByCharacterTests
-				test.r = int(r)
+				test.r = rune(r)
 			}
 			var buf [utf8.UTFMax]byte
 			sz := utf8.EncodeRune(buf[:], rune(r))
@@ -242,9 +242,9 @@ func doConformanceTests(t *Test, partn int) {

 func CharacterByCharacterTests() {
 	tests := part[1].tests
-	last := 0
+	var last rune = 0
 	for i := 0; i <= len(tests); i++ { // last one is special case
-		var r int
+		var r rune
 		if i == len(tests) {
 			r = 0x2FA1E // Don't have to go to 0x10FFFF
 		} else {

コアとなるコードの解説

このコミットの核心は、int 型で宣言されていた変数を rune 型に修正することです。

  1. test.r = rune(r): loadTestData() 関数は、おそらく外部のテストデータファイルからUnicodeコードポイントを読み込んでいます。r は読み込まれたコードポイントを表す変数であり、test.r はそのコードポイントを構造体 test のフィールドに保存するためのものです。元のコードでは int(r)int 型にキャストしていましたが、rune 型として扱うべき値を rune 型として保存することで、データの意味論的な整合性を保ちます。

  2. var last rune = 0: CharacterByCharacterTests() 関数は、文字単位でテストを行う際に、前の文字のコードポイントを last 変数に保持していると考えられます。文字コードポイントは rune 型で表現するのが適切であるため、int から rune に変更されました。初期値 0 はUnicodeのNULL文字(U+0000)を表し、rune 型として有効です。

  3. var r rune: 同じく CharacterByCharacterTests() 関数内で、現在のテスト対象の文字コードポイントを保持する r 変数も int から rune に変更されました。これにより、r が常にUnicodeコードポイントとして正しく解釈され、utf8.EncodeRune などの関数に渡される際にも型の一貫性が保たれます。

これらの変更は、Go言語の rune 型の導入意図に沿ったものであり、Unicode文字を扱うコードの正確性、可読性、および保守性を向上させます。特に、Unicode正規化のような文字の厳密な処理が求められる文脈では、適切な型を使用することが非常に重要です。

関連リンク

参考にした情報源リンク

  • Go言語の公式ドキュメント
  • Unicode Consortiumの公式ウェブサイト
  • Go言語のソースコードリポジトリ (特に src/pkg/exp/norm ディレクトリ)
  • Go言語に関する技術ブログやフォーラムでの議論 (当時の情報を含む)
  • コミットメッセージに記載されている Go Gerrit の変更リスト (CL): https://golang.org/cl/5472067 (現在は https://go.dev/cl/5472067 にリダイレクトされる可能性が高い)
    • このCLページで、より詳細な議論や背景情報が提供されている可能性があります。