[インデックス 17585] ファイルの概要
このコミットは、Go言語のgo/token
パッケージにおけるRemoveLine
関数の名称をMergeLine
に変更し、そのドキュメンテーションを改善するものです。この変更は、既存の関数の振る舞いをより正確に反映させ、利用者がその意図を誤解しないようにすることを目的としています。特に、行を「削除」するのではなく、次の行と「結合」するという機能のニュアンスを明確にしています。
コミット
commit 1ea0c480dc16a986c2c335ff2965e70d99bfa654
Author: Josh Bleecher Snyder <josharian@gmail.com>
Date: Thu Sep 12 09:31:07 2013 -0700
go/token: rename RemoveLine to MergeLine, improve documentation
This is a follow-up to feedback from gri in
https://golang.org/cl/12837044/. Most of the wording
and naming improvements are lifted shamelessly from him.
R=gri
CC=golang-dev
https://golang.org/cl/13670043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/1ea0c480dc16a986c2c335ff2965e70d99bfa654
元コミット内容
このコミットは、go/token
パッケージ内のFile
構造体のメソッドであるRemoveLine
をMergeLine
にリネームし、そのドキュメンテーションを大幅に改善しています。また、go/ast
パッケージ内でこの関数を呼び出している箇所も、新しい関数名に合わせて更新されています。
具体的な変更点は以下の通りです。
src/pkg/go/token/position.go
File
構造体のlines
フィールドのコメントが追加され、その役割が明確化されました。RemoveLine
関数がMergeLine
にリネームされました。MergeLine
関数のドキュメンテーションが、その実際の動作(行を次の行と結合する)をより正確に説明するように書き換えられました。- 無効な行番号が指定された場合にパニックを引き起こすためのバリデーションチェックが追加されました。
- ミューテックスのアンロック処理が
defer
ステートメントに移動され、ロックの解放が保証されるようになりました。
src/pkg/go/ast/import.go
fset.File(...).RemoveLine(...)
の呼び出しがfset.File(...).MergeLine(...)
に更新されました。
変更の背景
このコミットは、Goのコードベースにおける命名の一貫性と明確性を向上させるためのものです。元の関数名RemoveLine
は、その機能が「行を削除する」というよりも「行を次の行と結合する」という実態と乖離していました。これは、Goのソースコードを解析し、抽象構文木(AST)を構築する際に、行番号の管理が非常に重要であるため、誤解を招く可能性がありました。
コミットメッセージによると、この変更はgri
からのフィードバックに基づいています。golang.org/cl/12837044/
で議論された内容が、この命名とドキュメンテーションの改善に繋がったとされています。goimports
のようなツールがソースコードを整形する際に、行の結合が必要となるシナリオがあり、その際の内部的な行管理のロジックをより正確に表現するために、このリネームとドキュメンテーションの改善が行われました。
前提知識の解説
このコミットを理解するためには、以下のGo言語の概念とパッケージに関する知識が必要です。
-
go/token
パッケージ: Go言語のソースコードにおけるトークン(キーワード、識別子、演算子など)の位置情報(ファイル名、行番号、列番号、オフセット)を管理するためのパッケージです。FileSet
とFile
という主要な型を提供します。token.FileSet
: 複数のソースファイルにわたる位置情報を一元的に管理するセットです。各ファイルはFileSet
に登録され、一意のIDが割り当てられます。token.File
: 個々のソースファイルに関する位置情報(ファイル名、サイズ、行オフセットなど)を保持します。lines
フィールドは、各行の開始オフセットを格納するスライスであり、これによって行番号からファイル内のバイトオフセットを効率的に計算できます。token.Pos
: ソースコード内の特定の位置を表す抽象的な型です。通常、FileSet
と組み合わせて具体的なファイル名、行番号、列番号に変換されます。token.Position
:token.Pos
を具体的なファイル名、行番号、列番号、オフセットに変換した構造体です。
-
go/ast
パッケージ: Go言語のソースコードの抽象構文木(AST: Abstract Syntax Tree)を表現するためのパッケージです。go/parser
パッケージによって生成されたASTは、このパッケージの型で表現されます。ASTは、プログラムの構造を木構造で表現したもので、コンパイラ、リンター、コード整形ツールなどがコードを理解し、操作するために使用します。ast.File
: Goのソースファイル全体のASTを表すルートノードです。ast.ImportSpec
:import
宣言内の個々のインポートパスを表すノードです。
-
行オフセットと行番号: Goのソースコードでは、各行の開始位置はファイル内のバイトオフセットで管理されます。
token.File
のlines
スライスは、これらのオフセットを格納しており、これにより特定の行番号に対応するオフセットを素早く見つけることができます。行を「削除」または「結合」するという操作は、このlines
スライスを操作することで実現されます。 -
goimports
ツール: Goの標準ツールの一つで、Goのソースファイルを整形し、インポート文を自動的に追加、削除、整理する機能を提供します。このツールはgo/parser
とgo/ast
パッケージを利用してASTを操作し、go/token
パッケージで位置情報を管理します。このコミットで変更されたMergeLine
関数は、goimports
のようなツールがインポートブロックを整形する際に、不要な空行を削除したり、インポート文を結合したりする内部処理で利用される可能性があります。
技術的詳細
このコミットの技術的な核心は、go/token.File
構造体における行管理のセマンティクスを明確化することにあります。
token.File
構造体は、ソースファイル内の各行の開始オフセットをlines
という[]int
スライスで保持しています。例えば、lines[0]
はファイルの開始オフセット(通常は0)、lines[1]
は2行目の開始オフセット、といった具合です。
元のRemoveLine
関数は、指定された行番号に対応するlines
スライス内のエントリを削除していました。これにより、その行が「存在しない」かのように扱われ、後続の行が1つ前の行に「結合」されたかのような効果が得られます。しかし、「Remove」という名前は、ソースコードのテキスト自体から行が物理的に削除されるという誤解を招く可能性がありました。実際には、この操作は行のオフセット情報を変更するだけであり、ソースコードのテキスト内容には直接影響を与えません。
新しいMergeLine
という名前は、この動作をより正確に表現しています。つまり、指定された行の改行文字が、あたかもスペースに置き換えられたかのように、その行が次の行と論理的に結合されることを意味します。これにより、後続の行のオフセットが調整され、行番号が再割り当てされますが、ファイル全体のバイトオフセットは維持されます。これは、goimports
のようなツールが、インポートブロック内の空行を削除したり、重複するインポートを結合したりする際に、ソースコードの物理的な変更を伴わずに、行番号の整合性を保つために重要な機能です。
また、MergeLine
関数には、無効な行番号が渡された場合にpanic
を引き起こすための堅牢なチェックが追加されました。これは、APIの誤用を防ぎ、デバッグを容易にするための重要な改善です。
src/pkg/go/ast/import.go
における変更は、go/ast
パッケージがgo/token
パッケージの新しいAPIを使用するように適応したものです。このファイルは、Goのインポート宣言をソートするロジックを含んでおり、インポートブロック内の不要な空行や重複するインポートを処理する際に、MergeLine
の機能を利用しています。例えば、SortImports
関数内で、インポートグループの閉じ括弧の行が、最後のインポートスペックの行から2行以上離れている場合(つまり間に空行がある場合)、その空行を「マージ」して削除する処理が行われています。また、重複するインポートスペックを処理するsortSpecs
関数でも同様にMergeLine
が使用されています。
コアとなるコードの変更箇所
src/pkg/go/token/position.go
--- a/src/pkg/go/token/position.go
+++ b/src/pkg/go/token/position.go
@@ -97,7 +97,7 @@ type File struct {
size int // file size as provided to AddFile
// lines and infos are protected by set.mutex
- lines []int
+ lines []int // lines contains the offset of the first character for each line (the first entry is always 0)
infos []lineInfo
}
@@ -136,13 +136,27 @@ func (f *File) AddLine(offset int) {
f.set.mutex.Unlock()
}
-// RemoveLine removes a line by line number as reported by Position.Line.
+// MergeLine merges a line with the following line. It is akin to replacing
+// the newline character at the end of the line with a space (to not change the
+// remaining offsets). To obtain the line number, consult e.g. Position.Line.
+// MergeLine will panic if given an invalid line number.
//
-func (f *File) RemoveLine(line int) {
+func (f *File) MergeLine(line int) {
+ if line <= 0 {
+ panic("illegal line number (line numbering starts at 1)")
+ }
f.set.mutex.Lock()
+ defer f.set.mutex.Unlock()
+ if line >= len(f.lines) {
+ panic("illegal line number")
+ }
+ // To merge the line numbered <line> with the line numbered <line+1>,
+ // we need to remove the entry in lines corresponding to the line
+ // numbered <line+1>. The entry in lines corresponding to the line
+ // numbered <line+1> is located at index <line>, since indices in lines
+ // are 0-based and line numbers are 1-based.
copy(f.lines[line:], f.lines[line+1:])
f.lines = f.lines[:len(f.lines)-1]
- f.set.mutex.Unlock()
}
// SetLines sets the line offsets for a file and returns true if successful.
src/pkg/go/ast/import.go
--- a/src/pkg/go/ast/import.go
+++ b/src/pkg/go/ast/import.go
@@ -44,7 +44,7 @@ func SortImports(fset *token.FileSet, f *File) {
lastSpec := d.Specs[len(d.Specs)-1]
lastLine := fset.Position(lastSpec.Pos()).Line
if rParenLine := fset.Position(d.Rparen).Line; rParenLine > lastLine+1 {
- fset.File(d.Rparen).RemoveLine(rParenLine - 1)
+ fset.File(d.Rparen).MergeLine(rParenLine - 1)
}
}
}
@@ -146,7 +146,7 @@ func sortSpecs(fset *token.FileSet, f *File, specs []Spec) []Spec {
deduped = append(deduped, s)
} else {
p := s.Pos()
- fset.File(p).RemoveLine(fset.Position(p).Line)
+ fset.File(p).MergeLine(fset.Position(p).Line)
}
}
specs = deduped
コアとなるコードの解説
src/pkg/go/token/position.go
の変更点
-
lines
フィールドのコメント追加:lines []int
の行に// lines contains the offset of the first character for each line (the first entry is always 0)
というコメントが追加されました。これは、lines
スライスが各行の開始オフセットを格納していることを明確にし、その最初の要素が常に0であることを示しています。これにより、このフィールドの役割がより理解しやすくなりました。 -
RemoveLine
からMergeLine
へのリネームとドキュメンテーションの改善: 関数名がRemoveLine
からMergeLine
に変更されました。新しいドキュメンテーションは、この関数の動作を非常に詳細かつ正確に説明しています。MergeLine merges a line with the following line.
(行を次の行と結合する)It is akin to replacing the newline character at the end of the line with a space (to not change the remaining offsets).
(これは、行末の改行文字をスペースに置き換えることに似ており、残りのオフセットを変更しない)To obtain the line number, consult e.g. Position.Line.
(行番号を取得するには、例えばPosition.Line
を参照する)MergeLine will panic if given an invalid line number.
(無効な行番号が与えられた場合、MergeLine
はパニックを引き起こす) この説明により、関数が物理的に行を削除するのではなく、行のオフセット情報を操作して論理的に行を結合するものであることが明確になります。
-
引数バリデーションの追加:
if line <= 0 { panic("illegal line number (line numbering starts at 1)") }
とif line >= len(f.lines) { panic("illegal line number") }
という2つのバリデーションチェックが追加されました。これにより、MergeLine
関数が不正な行番号で呼び出された場合に、早期にエラーを検出し、プログラムのクラッシュを防ぐか、デバッグを容易にします。行番号は1から始まるため、0以下の値は不正です。また、f.lines
スライスの範囲外のインデックスも不正です。 -
ミューテックスの
defer
化:f.set.mutex.Unlock()
がdefer f.set.mutex.Unlock()
に変更されました。これにより、関数の実行がどのように終了しても(正常終了、return
、panic
など)、ミューテックスが確実に解放されるようになります。これは、並行処理におけるデッドロックやリソースリークを防ぐためのベストプラクティスです。 -
内部ロジックのコメント追加:
copy(f.lines[line:], f.lines[line+1:])
とf.lines = f.lines[:len(f.lines)-1]
の前に、// To merge the line numbered <line> with the line numbered <line+1>, ...
という詳細なコメントが追加されました。このコメントは、行を結合するためにlines
スライスから対応するエントリを削除する理由と、そのインデックス計算のロジックを説明しています。具体的には、1-basedの行番号line
に対応するlines
スライスのインデックスはline-1
であり、line+1
行目を結合するためには、line
番目のインデックスにあるエントリ(つまりline+1
行目の開始オフセット)を削除する必要があることを示しています。
src/pkg/go/ast/import.go
の変更点
このファイルでは、go/token.File
のRemoveLine
メソッドの呼び出しが、新しいMergeLine
メソッドの呼び出しに単純に置き換えられています。これは、go/ast
パッケージがgo/token
パッケージのAPI変更に適応したことを示しています。
SortImports
関数内では、インポートグループの閉じ括弧の行と最後のインポートスペックの行の間に空行がある場合、その空行を削除するためにMergeLine
が使用されます。sortSpecs
関数内では、重複するインポートスペックを処理する際に、重複したインポートの行を「マージ」するためにMergeLine
が使用されます。
これらの変更は、goimports
のようなツールがGoのソースコードを整形する際に、行番号の整合性を保ちつつ、不要な空行や重複するインポートを効率的に処理するための基盤を提供します。
関連リンク
- Go言語の
go/token
パッケージのドキュメンテーション: https://pkg.go.dev/go/token - Go言語の
go/ast
パッケージのドキュメンテーション: https://pkg.go.dev/go/ast - Go言語の
goimports
ツール: https://pkg.go.dev/golang.org/x/tools/cmd/goimports
参考にした情報源リンク
- 元のフィードバックがあったGoのChange List (CL): https://golang.org/cl/12837044/
- このコミットに対応するGoのChange List (CL): https://golang.org/cl/13670043
- Go言語のソースコード(GitHubリポジトリ): https://github.com/golang/go
- Go言語の公式ドキュメンテーション: https://go.dev/doc/
- Go言語の
go/token
パッケージのFile
構造体に関する議論(Stack Overflowなど、一般的なGoの知識源) - Go言語のASTとツールに関する一般的な情報源(ブログ記事、チュートリアルなど)
[インデックス 17585] ファイルの概要
このコミットは、Go言語のgo/token
パッケージにおけるRemoveLine
関数の名称をMergeLine
に変更し、そのドキュメンテーションを改善するものです。この変更は、既存の関数の振る舞いをより正確に反映させ、利用者がその意図を誤解しないようにすることを目的としています。特に、行を「削除」するのではなく、次の行と「結合」するという機能のニュアンスを明確にしています。
コミット
commit 1ea0c480dc16a986c2c335ff2965e70d99bfa654
Author: Josh Bleecher Snyder <josharian@gmail.com>
Date: Thu Sep 12 09:31:07 2013 -0700
go/token: rename RemoveLine to MergeLine, improve documentation
This is a follow-up to feedback from gri in
https://golang.org/cl/12837044/. Most of the wording
and naming improvements are lifted shamelessly from him.
R=gri
CC=golang-dev
https://golang.org/cl/13670043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/1ea0c480dc16a986c2c335ff2965e70d99bfa654
元コミット内容
このコミットは、go/token
パッケージ内のFile
構造体のメソッドであるRemoveLine
をMergeLine
にリネームし、そのドキュメンテーションを大幅に改善しています。また、go/ast
パッケージ内でこの関数を呼び出している箇所も、新しい関数名に合わせて更新されています。
具体的な変更点は以下の通りです。
src/pkg/go/token/position.go
File
構造体のlines
フィールドのコメントが追加され、その役割が明確化されました。RemoveLine
関数がMergeLine
にリネームされました。MergeLine
関数のドキュメンテーションが、その実際の動作(行を次の行と結合する)をより正確に説明するように書き換えられました。- 無効な行番号が指定された場合にパニックを引き起こすためのバリデーションチェックが追加されました。
- ミューテックスのアンロック処理が
defer
ステートメントに移動され、ロックの解放が保証されるようになりました。
src/pkg/go/ast/import.go
fset.File(...).RemoveLine(...)
の呼び出しがfset.File(...).MergeLine(...)
に更新されました。
変更の背景
このコミットは、Goのコードベースにおける命名の一貫性と明確性を向上させるためのものです。元の関数名RemoveLine
は、その機能が「行を削除する」というよりも「行を次の行と結合する」という実態と乖離していました。これは、Goのソースコードを解析し、抽象構文木(AST)を構築する際に、行番号の管理が非常に重要であるため、誤解を招く可能性がありました。
コミットメッセージによると、この変更はgri
からのフィードバックに基づいています。golang.org/cl/12837044/
で議論された内容が、この命名とドキュメンテーションの改善に繋がったとされています。このCLは、cmd/gofmt
(Goの標準コードフォーマッタ)のインポートソートロジックを強化し、重複するインポートを自動的に削除する機能を追加するものでした。この文脈において、行の「削除」ではなく「結合」という概念がより適切であると判断され、RemoveLine
の名称とドキュメンテーションの改善が求められました。goimports
のようなツールがソースコードを整形する際に、行の結合が必要となるシナリオがあり、その際の内部的な行管理のロジックをより正確に表現するために、このリネームとドキュメンテーションの改善が行われました。
前提知識の解説
このコミットを理解するためには、以下のGo言語の概念とパッケージに関する知識が必要です。
-
go/token
パッケージ: Go言語のソースコードにおけるトークン(キーワード、識別子、演算子など)の位置情報(ファイル名、行番号、列番号、オフセット)を管理するためのパッケージです。FileSet
とFile
という主要な型を提供します。token.FileSet
: 複数のソースファイルにわたる位置情報を一元的に管理するセットです。各ファイルはFileSet
に登録され、一意のIDが割り当てられます。token.File
: 個々のソースファイルに関する位置情報(ファイル名、サイズ、行オフセットなど)を保持します。lines
フィールドは、各行の開始オフセットを格納するスライスであり、これによって行番号からファイル内のバイトオフセットを効率的に計算できます。token.Pos
: ソースコード内の特定の位置を表す抽象的な型です。通常、FileSet
と組み合わせて具体的なファイル名、行番号、列番号に変換されます。token.Position
:token.Pos
を具体的なファイル名、行番号、列番号、オフセットに変換した構造体です。
-
go/ast
パッケージ: Go言語のソースコードの抽象構文木(AST: Abstract Syntax Tree)を表現するためのパッケージです。go/parser
パッケージによって生成されたASTは、このパッケージの型で表現されます。ASTは、プログラムの構造を木構造で表現したもので、コンパイラ、リンター、コード整形ツールなどがコードを理解し、操作するために使用します。ast.File
: Goのソースファイル全体のASTを表すルートノードです。ast.ImportSpec
:import
宣言内の個々のインポートパスを表すノードです。
-
行オフセットと行番号: Goのソースコードでは、各行の開始位置はファイル内のバイトオフセットで管理されます。
token.File
のlines
スライスは、これらのオフセットを格納しており、これにより特定の行番号に対応するオフセットを素早く見つけることができます。行を「削除」または「結合」するという操作は、このlines
スライスを操作することで実現されます。 -
gofmt
およびgoimports
ツール:gofmt
: Goの標準コードフォーマッタです。GoのソースコードをGoの公式スタイルガイドに沿って自動的に整形します。goimports
:gofmt
の機能を拡張し、Goのソースファイルを整形するだけでなく、インポート文を自動的に追加、削除、整理する機能を提供します。これらのツールはgo/parser
とgo/ast
パッケージを利用してASTを操作し、go/token
パッケージで位置情報を管理します。このコミットで変更されたMergeLine
関数は、goimports
のようなツールがインポートブロックを整形する際に、行の結合が必要となる内部処理で利用される可能性があります。
技術的詳細
このコミットの技術的な核心は、go/token.File
構造体における行管理のセマンティクスを明確化することにあります。
token.File
構造体は、ソースファイル内の各行の開始オフセットをlines
という[]int
スライスで保持しています。例えば、lines[0]
はファイルの開始オフセット(通常は0)、lines[1]
は2行目の開始オフセット、といった具合です。
元のRemoveLine
関数は、指定された行番号に対応するlines
スライス内のエントリを削除していました。これにより、その行が「存在しない」かのように扱われ、後続の行が1つ前の行に「結合」されたかのような効果が得られます。しかし、「Remove」という名前は、ソースコードのテキスト自体から行が物理的に削除されるという誤解を招く可能性がありました。実際には、この操作は行のオフセット情報を変更するだけであり、ソースコードのテキスト内容には直接影響を与えません。
新しいMergeLine
という名前は、この動作をより正確に表現しています。つまり、指定された行の改行文字が、あたかもスペースに置き換えられたかのように、その行が次の行と論理的に結合されることを意味します。これにより、後続の行のオフセットが調整され、行番号が再割り当てされますが、ファイル全体のバイトオフセットは維持されます。これは、goimports
のようなツールが、インポートブロック内の空行を削除したり、重複するインポートを結合したりする際に、ソースコードの物理的な変更を伴わずに、行番号の整合性を保つために重要な機能です。
また、MergeLine
関数には、無効な行番号が渡された場合にpanic
を引き起こすための堅牢なチェックが追加されました。これは、APIの誤用を防ぎ、デバッグを容易にするための重要な改善です。具体的には、行番号が1未満の場合や、f.lines
スライスの範囲外の行番号が指定された場合にパニックが発生します。
src/pkg/go/ast/import.go
における変更は、go/ast
パッケージがgo/token
パッケージの新しいAPIを使用するように適応したものです。このファイルは、Goのインポート宣言をソートするロジックを含んでおり、インポートブロック内の不要な空行や重複するインポートを処理する際に、MergeLine
の機能を利用しています。例えば、SortImports
関数内で、インポートグループの閉じ括弧の行が、最後のインポートスペックの行から2行以上離れている場合(つまり間に空行がある場合)、その空行を「マージ」して削除する処理が行われています。また、重複するインポートスペックを処理するsortSpecs
関数でも同様にMergeLine
が使用されます。
コアとなるコードの変更箇所
src/pkg/go/token/position.go
--- a/src/pkg/go/token/position.go
+++ b/src/pkg/go/token/position.go
@@ -97,7 +97,7 @@ type File struct {
size int // file size as provided to AddFile
// lines and infos are protected by set.mutex
- lines []int
+ lines []int // lines contains the offset of the first character for each line (the first entry is always 0)
infos []lineInfo
}
@@ -136,13 +136,27 @@ func (f *File) AddLine(offset int) {
f.set.mutex.Unlock()
}
-// RemoveLine removes a line by line number as reported by Position.Line.
+// MergeLine merges a line with the following line. It is akin to replacing
+// the newline character at the end of the line with a space (to not change the
+// remaining offsets). To obtain the line number, consult e.g. Position.Line.
+// MergeLine will panic if given an invalid line number.
//
-func (f *File) RemoveLine(line int) {
+func (f *File) MergeLine(line int) {
+ if line <= 0 {
+ panic("illegal line number (line numbering starts at 1)")
+ }
f.set.mutex.Lock()
+ defer f.set.mutex.Unlock()
+ if line >= len(f.lines) {
+ panic("illegal line number")
+ }
+ // To merge the line numbered <line> with the line numbered <line+1>,
+ // we need to remove the entry in lines corresponding to the line
+ // numbered <line+1>. The entry in lines corresponding to the line
+ // numbered <line+1> is located at index <line>, since indices in lines
+ // are 0-based and line numbers are 1-based.
copy(f.lines[line:], f.lines[line+1:])
f.lines = f.lines[:len(f.lines)-1]
- f.set.mutex.Unlock()
}
// SetLines sets the line offsets for a file and returns true if successful.
src/pkg/go/ast/import.go
--- a/src/pkg/go/ast/import.go
+++ b/src/pkg/go/ast/import.go
@@ -44,7 +44,7 @@ func SortImports(fset *token.FileSet, f *File) {
lastSpec := d.Specs[len(d.Specs)-1]
lastLine := fset.Position(lastSpec.Pos()).Line
if rParenLine := fset.Position(d.Rparen).Line; rParenLine > lastLine+1 {
- fset.File(d.Rparen).RemoveLine(rParenLine - 1)
+ fset.File(d.Rparen).MergeLine(rParenLine - 1)
}
}
}
@@ -146,7 +146,7 @@ func sortSpecs(fset *token.FileSet, f *File, specs []Spec) []Spec {
deduped = append(deduped, s)
} else {
p := s.Pos()
- fset.File(p).RemoveLine(fset.Position(p).Line)
+ fset.File(p).MergeLine(fset.Position(p).Line)
}
}
specs = deduped
コアとなるコードの解説
src/pkg/go/token/position.go
の変更点
-
lines
フィールドのコメント追加:lines []int
の行に// lines contains the offset of the first character for each line (the first entry is always 0)
というコメントが追加されました。これは、lines
スライスが各行の開始オフセットを格納していることを明確にし、その最初の要素が常に0であることを示しています。これにより、このフィールドの役割がより理解しやすくなりました。 -
RemoveLine
からMergeLine
へのリネームとドキュメンテーションの改善: 関数名がRemoveLine
からMergeLine
に変更されました。新しいドキュメンテーションは、この関数の動作を非常に詳細かつ正確に説明しています。MergeLine merges a line with the following line.
(行を次の行と結合する)It is akin to replacing the newline character at the end of the line with a space (to not change the remaining offsets).
(これは、行末の改行文字をスペースに置き換えることに似ており、残りのオフセットを変更しない)To obtain the line number, consult e.g. Position.Line.
(行番号を取得するには、例えばPosition.Line
を参照する)MergeLine will panic if given an invalid line number.
(無効な行番号が与えられた場合、MergeLine
はパニックを引き起こす) この説明により、関数が物理的に行を削除するのではなく、行のオフセット情報を操作して論理的に行を結合するものであることが明確になります。
-
引数バリデーションの追加:
if line <= 0 { panic("illegal line number (line numbering starts at 1)") }
とif line >= len(f.lines) { panic("illegal line number") }
という2つのバリデーションチェックが追加されました。これにより、MergeLine
関数が不正な行番号で呼び出された場合に、早期にエラーを検出し、プログラムのクラッシュを防ぐか、デバッグを容易にします。行番号は1から始まるため、0以下の値は不正です。また、f.lines
スライスの範囲外のインデックスも不正です。 -
ミューテックスの
defer
化:f.set.mutex.Unlock()
がdefer f.set.mutex.Unlock()
に変更されました。これにより、関数の実行がどのように終了しても(正常終了、return
、panic
など)、ミューテックスが確実に解放されるようになります。これは、並行処理におけるデッドロックやリソースリークを防ぐためのベストプラクティスです。 -
内部ロジックのコメント追加:
copy(f.lines[line:], f.lines[line+1:])
とf.lines = f.lines[:len(f.lines)-1]
の前に、// To merge the line numbered <line> with the line numbered <line+1>, ...
という詳細なコメントが追加されました。このコメントは、行を結合するためにlines
スライスから対応するエントリを削除する理由と、そのインデックス計算のロジックを説明しています。具体的には、1-basedの行番号line
に対応するlines
スライスのインデックスはline-1
であり、line+1
行目を結合するためには、line
番目のインデックスにあるエントリ(つまりline+1
行目の開始オフセット)を削除する必要があることを示しています。
src/pkg/go/ast/import.go
の変更点
このファイルでは、go/token.File
のRemoveLine
メソッドの呼び出しが、新しいMergeLine
メソッドの呼び出しに単純に置き換えられています。これは、go/ast
パッケージがgo/token
パッケージのAPI変更に適応したことを示しています。
SortImports
関数内では、インポートグループの閉じ括弧の行と最後のインポートスペックの行の間に空行がある場合、その空行を削除するためにMergeLine
が使用されます。sortSpecs
関数内では、重複するインポートスペックを処理する際に、重複したインポートの行を「マージ」するためにMergeLine
が使用されます。
これらの変更は、goimports
のようなツールがGoのソースコードを整形する際に、行番号の整合性を保ちつつ、不要な空行や重複するインポートを効率的に処理するための基盤を提供します。
関連リンク
- Go言語の
go/token
パッケージのドキュメンテーション: https://pkg.go.dev/go/token - Go言語の
go/ast
パッケージのドキュメンテーション: https://pkg.go.dev/go/ast - Go言語の
goimports
ツール: https://pkg.go.dev/golang.org/x/tools/cmd/goimports
参考にした情報源リンク
- 元のフィードバックがあったGoのChange List (CL): https://golang.org/cl/12837044/
- このコミットに対応するGoのChange List (CL): https://golang.org/cl/13670043
- Go言語のソースコード(GitHubリポジトリ): https://github.com/golang/go
- Go言語の公式ドキュメンテーション: https://go.dev/doc/