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

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

このコミットは、Go言語のバージョン1.1に関する公式ドキュメントである doc/go1.1.html ファイルの更新です。具体的には、bufio.Scanner の導入、reflect パッケージの機能拡張、そしてUnicodeサロゲートペアの取り扱いに関する変更点が追記されています。

コミット

commit d88133137bcab6839d1f1cab0d4b9edb30381b41
Author: Rob Pike <r@golang.org>
Date:   Thu Mar 21 22:37:13 2013 -0700

    go1.1.html: bufio.Scanner and reflect; more about surrogates

    R=golang-dev, adg
    CC=golang-dev
    https://golang.org/cl/7958043

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

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

元コミット内容

このコミットの元の内容は、Go 1.1のリリースノートである go1.1.html に、以下の主要な変更点を追記することです。

  1. bufio.Scanner の追加: テキスト入力の走査を簡素化するための新しい型 bufio.Scanner の導入。
  2. reflect パッケージの拡張: reflect パッケージに Select, ChanOf, MakeFunc, MapOf, SliceOf, Convert, Type.ConvertibleTo などの新機能が追加されたこと。
  3. Unicodeサロゲートペアの取り扱い: Unicodeサロゲートハーフ値がruneおよび文字列定数で不正と見なされるようになったこと。

変更の背景

Go 1.1は、Go言語の重要なマイルストーンとなるリリースであり、パフォーマンスの向上、言語仕様の微調整、標準ライブラリの機能強化が図られました。このコミットは、そのGo 1.1のリリースノートの一部として、ユーザーが新しい機能や変更点を理解できるようにするためのドキュメント更新です。

特に、bufio パッケージの既存のテキスト走査ルーチン(ReadBytes, ReadString, ReadLine)が、単純な用途には複雑すぎると認識されていました。これを解決するために、より使いやすく、一般的なユースケースに対応できる bufio.Scanner が導入されました。

また、reflect パッケージは、Goの型システムを動的に操作するための強力なツールですが、特定の高度な操作(例えば、select ステートメントの動的な実行や、型変換の動的な処理)には機能が不足していました。これらのニーズに応えるため、reflect パッケージが拡張されました。

Unicodeのサロゲートペアに関する変更は、Go言語がUnicodeを正しく、かつ安全に扱うための継続的な取り組みの一環です。不正なサロゲートペアが定数として扱われることを防ぎ、より堅牢な文字列処理を保証するための修正です。

前提知識の解説

Go言語のバージョン管理とリリースサイクル

Go言語は、定期的に新しいバージョンがリリースされます。Go 1.x系は後方互換性を重視しており、既存のコードが新しいバージョンでも動作するように設計されています。Go 1.1は、Go 1の最初のマイナーアップデートであり、パフォーマンスの改善と新機能の追加が行われました。

bufio パッケージ

bufio パッケージは、I/O操作をバッファリングすることで効率化するための機能を提供します。bufio.Reader は、ファイルやネットワーク接続からの読み込みを効率的に行うためのメソッドを提供しますが、行単位や単語単位での読み込みは、エラーハンドリングや終端処理が複雑になることがありました。

reflect パッケージ

reflect パッケージは、Goプログラムが実行時に自身の構造を検査し、操作するための機能を提供します。これにより、ジェネリックなプログラミングや、異なる型のデータを扱うライブラリの作成が可能になります。例えば、JSONエンコーダ/デコーダやORM(Object-Relational Mapping)ライブラリなどは、reflect パッケージを多用します。

Unicodeとサロゲートペア

Unicodeは、世界中の文字を統一的に扱うための文字コード標準です。UTF-8は、Unicode文字をバイト列にエンコードするための可変長エンコーディング方式です。 サロゲートペア(Surrogate Pair)は、UTF-16エンコーディングにおいて、基本多言語面(BMP: Basic Multilingual Plane)に含まれない文字(U+10000からU+10FFFFの範囲の文字)を表現するために使用される2つの16ビットコードポイントの組み合わせです。具体的には、U+D800からU+DBFFの範囲(上位サロゲート)と、U+DC00からU+DFFFの範囲(下位サロゲート)のコードポイントが組み合わされて1つの文字を表します。 Go言語では、文字列はUTF-8でエンコードされたバイト列として扱われ、rune 型はUnicodeコードポイントを表します。不正なサロゲートハーフ値(単独で存在するサロゲートコードポイント)は、有効なUnicode文字ではありません。

技術的詳細

bufio.Scanner

bufio.Scanner は、io.Reader からの入力を、行、単語、またはカスタムの区切り文字で簡単に走査するための新しいインターフェースを提供します。主な特徴は以下の通りです。

  • シンプルさ: ReadLine などの既存のメソッドよりも、一般的なテキスト走査のユースケースを大幅に簡素化します。
  • エラーハンドリング: 長すぎる行などの問題のある入力に対して、自動的に走査を終了し、エラーを報告します。これにより、無限ループやメモリ枯渇のリスクを軽減します。
  • 柔軟性: SplitFunc を使用することで、行区切り(デフォルト)、単語区切り、またはユーザー定義のカスタム区切りで入力を分割できます。
  • メモリ効率: 内部的にバッファを再利用することで、効率的なメモリ使用を実現します。

提供されたコード例は、標準入力から行を読み込み、それを標準出力に表示する典型的な bufio.Scanner の使用方法を示しています。

scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
    fmt.Println(scanner.Text()) // Println will add back the final '\n'
}
if err := scanner.Err(); err != nil {
    fmt.Fprintln(os.Stderr, "reading standard input:", err)
}

このコードは、scanner.Scan() が次のトークン(デフォルトでは行)を読み込むたびに true を返し、読み込みが終了するかエラーが発生すると false を返します。scanner.Text() は読み込まれたトークンを文字列として返します。ループ終了後、scanner.Err() をチェックすることで、読み込み中に発生したエラーを確認できます。

reflect パッケージの拡張

reflect パッケージには、以下の重要な機能が追加されました。

  1. reflect.Selectreflect.SelectCase:

    • Goの select ステートメントは、複数のチャネル操作を同時に待ち受けるための強力な構文です。Go 1.1では、この select の機能を reflect パッケージを通じて動的に実行できるようになりました。
    • reflect.SelectCase は、select ステートメントの各ケース(チャネルの送受信操作)を表現します。
    • reflect.Select 関数は、これらの SelectCase のスライスを受け取り、実際の select 操作を実行します。これにより、実行時に動的にチャネル操作を構築し、待ち受けることが可能になります。これは、汎用的な並行処理ライブラリやフレームワークを構築する際に非常に有用です。
  2. Value.ConvertType.ConvertibleTo:

    • Value.Convert(Type) メソッドは、reflect.Value が表す値を、指定された Type にGoの型変換規則に従って変換します。これは、例えば intinterface{} に変換するような、Go言語が許容する明示的または暗黙的な型変換を動的に実行する際に役立ちます。
    • Type.ConvertibleTo(Type) メソッドは、ある型が別の型に変換可能かどうかをテストします。
  3. reflect.MakeFunc:

    • この関数は、既存の reflect.Value のスライスを引数として受け取り、新しい関数を作成します。この新しい関数は、呼び出された際に、提供された reflect.Value を適切なGoの型に変換して、元の関数に渡します。
    • これにより、動的に引数の型を調整して関数を呼び出すような、より柔軟な関数呼び出しメカニズムを構築できます。例えば、interface{} 型の引数を受け取る関数に対して、int 型の reflect.Value を渡す際に、自動的に型変換が行われるように設定できます。
  4. reflect.ChanOf, reflect.MapOf, reflect.SliceOf:

    • これらの関数は、既存の reflect.Type から、新しいチャネル型、マップ型、またはスライス型を動的に構築します。
    • 例えば、reflect.SliceOf(reflect.TypeOf(0))[]int 型の reflect.Type を返します。これにより、実行時に未知の要素型を持つコレクション型を生成する必要がある場合に非常に便利です。

Unicodeサロゲートペアの取り扱い

Go 1.1では、Unicodeのサロゲートハーフ値(\ud800 など)が、runeおよび文字列定数として直接記述された場合に、コンパイラによって拒否されるようになりました。これは、これらの値が単独では有効なUnicode文字ではないためです。

しかし、UTF-8エンコードされたバイト列として明示的に記述された場合(例: "\xed\xa0\x80")、そのような文字列は引き続き作成可能です。これは、Goの文字列がバイト列のシーケンスであるという性質を反映しています。

重要な変更点は、そのような不正なバイト列が range ループなどでruneのシーケンスとしてデコードされる場合、utf8.RuneError (U+FFFD) が生成されるようになったことです。これは、不正なUTF-8シーケンスや、単独のサロゲートハーフ値が検出された場合に、Goが標準的な「置換文字」を返すことで、プログラムが不正な文字を誤って処理するのを防ぐための堅牢な動作です。

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

このコミットは、Go言語のドキュメントファイル doc/go1.1.html のみを変更しています。

--- a/doc/go1.1.html
+++ b/doc/go1.1.html
@@ -81,8 +81,8 @@ For example,
 The language allows the implementation to choose whether the <code>int</code> type and
 <code>uint</code> types are 32 or 64 bits. Previous Go implementations made <code>int</code>
 and <code>uint</code> 32 bits on all systems. Both the gc and gccgo implementations
-<a href="http://golang.org/issue/2188">now make
-<code>int</code> and <code>uint</code> 64 bits on 64-bit platforms such as AMD64/x86-64</a>.
+now make
+<code>int</code> and <code>uint</code> 64 bits on 64-bit platforms such as AMD64/x86-64.
 Among other things, this enables the allocation of slices with
 more than 2 billion elements on 64-bit platforms.
 </p>
@@ -144,6 +144,15 @@ func main() {
 printed <code>"\\ud800"</code> in Go 1.0, but prints <code>"\\ufffd"</code> in Go 1.1.
 </p>
 
+<p>
+Surrogate-half Unicode values are now illegal in rune and string constants, so constants such as
+<code>'\\ud800'</code> and <code>"\\ud800"</code> are now rejected by the compilers.
+When written explicitly as UTF-8 encoded bytes,
+such strings can still be created, as in <code>"\\xed\\xa0\\x80"</code>.
+However, when such a string is decoded as a sequence of runes, as in a range loop, it will yield only <code>utf8.RuneError</code>
+values.
+</p>
+
 <p>
 The Unicode byte order marks U+FFFE and U+FEFF, encoded in UTF-8, are now permitted as the first
 character of a Go source file.\n@@ -255,7 +264,39 @@ TODO introduction
 <h3 id="bufio_scanner">bufio.Scanner</h3>
 
 <p>
-TODO
+The various routines to scan textual input in the
+<a href="/pkg/bufio/"><code>bufio</code></a>
+package,
+<a href="/pkg/bufio/#Reader.ReadBytes"><code>ReadBytes</code></a>,
+<a href="/pkg/bufio/#Reader.ReadString"><code>ReadString</code></a>
+and particularly
+<a href="/pkg/bufio/#Reader.ReadLine"><code>ReadLine</code></a>,
+are needlessly complex to use for simple purposes.
+In Go 1.1, a new type,
+<a href="/pkg/bufio/#Scanner"><code>Scanner</code></a>,
+has been added to make it easier to do simple tasks such as
+read the input as a sequence of lines or space-delimited words.
+It simplifies the problem by terminating the scan on problematic
+input such as pathologically long lines, and having a simple
+default: line-oriented input, with each line stripped of its terminator.
+Here is code to reproduce the input a line at a time:
+</p>
+
+<pre>
+scanner := bufio.NewScanner(os.Stdin)
+for scanner.Scan() {
+    fmt.Println(scanner.Text()) // Println will add back the final '\n'
+}
+if err := scanner.Err(); err != nil {
+    fmt.Fprintln(os.Stderr, "reading standard input:", err)
+}
+</pre>
+
+<p>
+Scanning behavior can be adjusted through a function to control subdividing the input
+(see the documentation for <a href="/pkg/bufio/#SplitFunc"><code>SplitFunc</code></a>),
+but for tough problems or the need to continue past errors, the older interface
+may still be required.
 </p>
 
 <h3 id="net">net</h3>
@@ -293,10 +334,52 @@ methods.
 <h3 id="reflect">reflect</h3>
 
 <p>
-TODO: 
-<code>reflect</code>: Select, ChanOf, MakeFunc, MapOf, SliceOf, Convert, Type.ConvertibleTo
+The <a href="/pkg/reflect/"><code>reflect</code></a> package has several significant additions.
 </p>
 
+<p>
+It is now possible to run a <code>select</code> statement using
+the <code>reflect</code> package; see the description of
+<a href="/pkg/reflect/#Select"><code>Select</code></a>
+and
+<a href="/pkg/reflect/#SelectCase"><code>SelectCase</code></a>
+for details.
+</p>
+
+<p>
+The new method
+<a href="/pkg/reflect/#Value.Convert"><code>Value.Convert</code></a>
+(or
+<a href="/pkg/reflect/#Type"><code>Type.ConvertibleTo</code></a>)
+provides functionality to execute a Go conversion or type assertion operation
+on a
+<a href="/pkg/reflect/#Value"><code>Value</code></a>
+(or test for its possibility).
+</p>
+
+<p>
+The new function
+<a href="/pkg/reflect/#MakeFunc"><code>MakeFunc</code></a>
+creates a wrapper function to make it easier to call a function with existing
+<a href="/pkg/reflect/#Value"><code>Values</code></a>,
+doing the standard Go conversions among the arguments, for instance
+to pass an actual <code>int</code> to a formal <code>interface{}</code>.
+</p>
+
+<p>
+Finally, the new functions
+<a href="/pkg/reflect/#ChanOf"><code>ChanOf</code></a>,
+<a href="/pkg/reflect/#MapOf"><code>MapOf</code></a>
+and
+<a href="/pkg/reflect/#SliceOf"><code>SliceOf</code></a>
+construct new
+<a href="/pkg/reflect/#Type"><code>Types</code></a>
+from existing types, for example to construct a the type <code>[]T</code> given
+only <code>T</code>.
+</p>
+
+
+
 <h3 id="runtime">runtime</h3>
 
 <p>

コアとなるコードの解説

このコミットは、Go 1.1のリリースノートである doc/go1.1.html に、以下の主要なセクションを追加・更新しています。

  1. int および uint の64ビットプラットフォームでのサイズに関する修正:

    • 以前のGoのバージョンでは、intuint はすべてのシステムで32ビットでした。Go 1.1からは、AMD64/x86-64のような64ビットプラットフォームでは64ビットになるという変更が加えられました。
    • このコミットでは、この変更に関する既存のドキュメントから、特定のissueへのリンク(<a href="http://golang.org/issue/2188">...</a>)が削除され、より簡潔な記述に変更されています。これは、情報がリリースノートに統合されたため、個別のissueへの参照が不要になったことを示唆しています。
  2. Unicodeサロゲートハーフ値の取り扱いに関する追記:

    • Go 1.1では、'\ud800'"\ud800" のようなサロゲートハーフ値を含むruneおよび文字列定数が、コンパイラによって不正と見なされ、拒否されるようになりました。
    • しかし、"\xed\xa0\x80" のようにUTF-8エンコードされたバイト列として明示的に記述された場合は、引き続き文字列として作成可能です。
    • 重要なのは、そのような文字列が range ループなどでruneのシーケンスとしてデコードされると、utf8.RuneError (U+FFFD) が生成されるようになった点です。これは、不正なUnicodeシーケンスに対するGoの堅牢なエラーハンドリングを示しています。
  3. bufio.Scanner の導入:

    • bufio パッケージの既存のテキスト走査ルーチン(ReadBytes, ReadString, ReadLine)が、単純な用途には複雑であるという問題意識から、新しい型 bufio.Scanner が導入されました。
    • Scanner は、行単位やスペース区切りの単語など、一般的なテキスト走査タスクを簡素化します。
    • 病的に長い行のような問題のある入力に対しても、走査を終了させることで堅牢性を高めています。
    • デフォルトでは行指向の入力(終端文字が取り除かれる)を提供し、SplitFunc を使用して走査動作を調整できる柔軟性も持ちます。
    • 簡単な使用例として、標準入力から行を読み込み、出力するGoコードが示されています。
  4. reflect パッケージの機能拡張:

    • reflect パッケージに複数の重要な追加が行われました。
    • reflect.Selectreflect.SelectCase: select ステートメントを reflect パッケージ経由で動的に実行できるようになりました。これにより、実行時にチャネル操作を動的に構築し、待ち受けることが可能になります。
    • Value.ConvertType.ConvertibleTo: reflect.Value が表す値を、Goの型変換規則に従って別の型に変換する機能、およびその変換が可能かどうかをテストする機能が追加されました。
    • reflect.MakeFunc: 既存の reflect.Value を引数として受け取り、新しい関数を作成する機能です。これにより、動的に引数の型を調整して関数を呼び出すような、より柔軟な関数呼び出しメカニズムを構築できます。
    • reflect.ChanOf, reflect.MapOf, reflect.SliceOf: これらの関数は、既存の reflect.Type から、新しいチャネル型、マップ型、またはスライス型を動的に構築する機能を提供します。これにより、実行時に未知の要素型を持つコレクション型を生成する必要がある場合に非常に便利です。

これらの変更は、Go 1.1が言語の使いやすさ、堅牢性、そして動的なプログラミング能力を向上させるための重要なステップであったことを示しています。

関連リンク

参考にした情報源リンク