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

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

このコミットは、Go言語の標準ライブラリ encoding/json パッケージ内の scanner.go ファイルにおけるコメントの修正に関するものです。具体的には、stateNeg 関数の説明が誤っていたのを訂正しています。

コミット

commit daf81ae78ee17bc4ef0992f399f39dc3122cc107
Author: Oliver Hookins <ohookins@gmail.com>
Date:   Fri Jul 5 14:26:09 2013 +1000

    encoding/json: Correct description of stateNeg function.
    
    R=golang-dev, dave, adg
    CC=golang-dev
    https://golang.org/cl/10862045
---
 src/pkg/encoding/json/scanner.go | 2 +-\
 1 file changed, 1 insertion(+), 1 deletion(-)\

diff --git a/src/pkg/encoding/json/scanner.go b/src/pkg/encoding/json/scanner.go
index 054b6b3d56..a4609c8950 100644
--- a/src/pkg/encoding/json/scanner.go
+++ b/src/pkg/encoding/json/scanner.go
@@ -390,7 +390,7 @@ func stateInStringEscU123(s *scanner, c int) int {\
 	return s.error(c, "in \\u hexadecimal character escape")
 }
 
-// stateInStringEscU123 is the state after reading `-` during a number.
+// stateNeg is the state after reading `-` during a number.
 func stateNeg(s *scanner, c int) int {\
  \tif c == '0' {\
  \t\ts.step = state0\

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

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

元コミット内容

encoding/json: Correct description of stateNeg function.

このコミットは、encoding/json パッケージ内の stateNeg 関数の説明を修正するものです。

変更の背景

Go言語の encoding/json パッケージは、JSONデータを効率的にパースするためのステートマシンベースのスキャナーを内部に持っています。このスキャナーは、入力されたJSON文字列を文字ごとに読み込み、現在の状態と読み込んだ文字に基づいて次の状態に遷移することで、JSONのトークン(数値、文字列、ブーリアン、構造文字など)を識別します。

scanner.go ファイルには、このステートマシンを構成する様々な状態関数が定義されています。stateNeg 関数もその一つで、JSONの数値リテラルをパースする際に、負の符号 (-) を読み込んだ直後の状態を処理する役割を担っています。

このコミットが行われる前は、stateNeg 関数のコメントが誤って stateInStringEscU123 関数に関する説明になっていました。これは単なるコメントの誤りであり、実際のコードの動作には影響を与えませんが、コードの可読性や理解を妨げる可能性がありました。このコミットは、その誤ったコメントを修正し、stateNeg 関数が実際に何をするのかを正確に記述することで、コードベースの品質とメンテナンス性を向上させることを目的としています。

前提知識の解説

JSON (JavaScript Object Notation)

JSONは、人間が読んで理解しやすく、機械が生成・解析しやすいデータ交換フォーマットです。主にウェブアプリケーションでデータを送受信する際に利用されます。JSONのデータ構造は、キーと値のペアの集まり(オブジェクト)と、値の順序付きリスト(配列)の2種類が基本です。

JSONの数値リテラルは、整数部、小数部、指数部から構成されます。負の数は、先頭にハイフン (-) を付けることで表現されます。例えば、-123, -0.5, -1.2e+3 などです。

ステートマシン (State Machine)

ステートマシンは、有限個の状態を持ち、特定のイベントや入力に基づいて状態を遷移させる抽象的なモデルです。各状態では、特定の処理が行われ、次の入力によってどの状態に遷移するかが決定されます。

JSONパーサーのような構文解析器では、ステートマシンがよく利用されます。入力ストリーム(JSON文字列)の各文字を読み込みながら、現在の文脈(状態)に応じて次の文字が有効かどうかを判断し、適切な状態に遷移していきます。これにより、複雑な文法を持つデータを効率的かつ正確に解析することができます。

Go言語の encoding/json パッケージ

Go言語の標準ライブラリ encoding/json は、Goのデータ構造とJSONデータの間で変換を行うための機能を提供します。このパッケージは、内部的にJSONスキャナーとパーサーを使用して、JSONデータのエンコード(Goのデータ構造からJSONへ)とデコード(JSONからGoのデータ構造へ)を行います。

scanner.go ファイルは、このパッケージの低レベルな部分を担っており、JSON文字列をトークンに分割する役割を負っています。これは、JSONの構文規則に従って文字のシーケンスを解釈し、数値、文字列、ブーリアン、null、オブジェクトの開始/終了、配列の開始/終了などの基本的なJSON要素を識別します。

scanner 構造体と状態関数

encoding/json パッケージの内部スキャナーは、scanner 構造体によって管理されます。この構造体は、現在のスキャン位置、エラー情報、そして現在の状態を示す step フィールドなどを含んでいます。

step フィールドは、func(*scanner, int) int 型の関数ポインタであり、現在の状態に対応する関数を指します。スキャナーは、入力文字を読み込むたびに、この step が指す関数を呼び出し、その関数の戻り値によって次の状態(次の状態関数)を決定します。

例えば、stateNeg 関数は、負の符号 (-) を読み込んだ直後に呼び出される状態関数です。この関数は、次に続く文字が数値として有効な文字であるか(0から9)をチェックし、それに応じて次の状態関数(state0state1など)を返します。もし有効な文字でなければ、エラー状態を返します。

技術的詳細

Goの encoding/json パッケージにおけるJSONスキャナーは、非常に効率的なステートマシンとして設計されています。これは、JSONの仕様に厳密に従いながら、バイト単位で入力を処理し、最小限のオーバーヘッドでトークンを識別します。

scanner.go 内の各 state 関数は、func(s *scanner, c int) int というシグネチャを持っています。

  • s *scanner: 現在のスキャナーの状態を保持するポインタです。
  • c int: 現在読み込んだ文字(rune)を表します。Goでは int 型でruneを表現します。
  • 戻り値 int: 次に呼び出すべき状態関数を識別するための整数値です。この整数値は、scanner 構造体の step フィールドに設定され、次の文字が読み込まれた際にその状態関数が呼び出されます。

stateNeg 関数の役割は、JSON数値のパースにおいて、負の符号 (-) の直後に続く文字を検証することです。JSONの数値リテラルの仕様では、負の符号の直後には数字が続く必要があります。

stateNeg 関数の内部ロジックは以下の通りです。

  1. c == '0' の場合: 読み込んだ文字 c'0' であれば、これは -0 のような形式の数値の始まりと解釈されます。この場合、スキャナーは state0 状態に遷移します。state0 は、0 の後に続く文字(小数点、指数部、または数値の終わり)を処理する状態です。
  2. '1' <= c && c <= '9' の場合: 読み込んだ文字 c'1' から '9' の間の数字であれば、これは -123 のような形式の数値の始まりと解釈されます。この場合、スキャナーは state1 状態に遷移します。state1 は、0 以外の数字の後に続く文字(他の数字、小数点、指数部、または数値の終わり)を処理する状態です。
  3. その他の場合: 上記のいずれでもない場合、つまり負の符号の直後に数字以外の文字が来た場合、これはJSONの数値リテラルとしては不正な形式です。この場合、stateNeg 関数は s.error(c, "in number") を呼び出してエラーを報告し、スキャナーをエラー状態に遷移させます。

このコミットは、この stateNeg 関数の直前にあったコメントが、誤って stateInStringEscU123 関数(文字列エスケープシーケンス内のUnicodeエスケープを処理する関数)の説明になっていたのを修正しました。これは、コードの機能には影響を与えないものの、ドキュメントとしての正確性を高める重要な修正です。

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

src/pkg/encoding/json/scanner.go ファイルの以下の行が変更されました。

--- a/src/pkg/encoding/json/scanner.go
+++ b/src/pkg/encoding/json/scanner.go
@@ -390,7 +390,7 @@ func stateInStringEscU123(s *scanner, c int) int {\
 	return s.error(c, "in \\u hexadecimal character escape")
 }
 
-// stateInStringEscU123 is the state after reading `-` during a number.
+// stateNeg is the state after reading `-` during a number.
 func stateNeg(s *scanner, c int) int {\
  \tif c == '0' {\
  \t\ts.step = state0\

具体的には、392行目のコメントが // stateInStringEscU123 is the state after reading - during a number. から // stateNeg is the state after reading - during a number. に変更されました。

コアとなるコードの解説

変更された行は、stateNeg 関数の直前にあるコメントです。

  • 変更前: // stateInStringEscU123 is the state after reading - during a number.
    • このコメントは、stateNeg 関数に関するものではなく、その直前の stateInStringEscU123 関数に関する説明が誤ってここにコピーされていたか、あるいは単なるタイプミスでした。stateInStringEscU123 は文字列内のUnicodeエスケープシーケンスを処理する関数であり、数値のパースとは無関係です。
  • 変更後: // stateNeg is the state after reading - during a number.
    • このコメントは、stateNeg 関数が実際に何をするのかを正確に記述しています。すなわち、数値のパース中に負の符号 (-) を読み込んだ後の状態を処理する関数であることを示しています。

この修正は、コードの動作には一切影響を与えませんが、コードベースのドキュメンテーションの正確性を向上させ、将来の開発者がこのコードを理解しやすくするために重要です。

関連リンク

参考にした情報源リンク