[インデックス 1194] ファイルの概要
このコミットは、Go言語の初期開発段階において、内部的に使用されていたvector
パッケージの利用を廃止し、代わりにarray
パッケージに移行した変更を記録しています。具体的には、正規表現エンジン(regexp
パッケージ)とテストコードにおいて、動的なデータ構造の管理にvector
ではなくarray
を使用するように修正されました。また、ビルドスクリプトであるmake.bash
も、この変更に合わせて更新されています。
コミット
commit bef9b1713a83f5d1722a2b01a73f2a6600fda43b
Author: Robert Griesemer <gri@golang.org>
Date: Wed Nov 19 15:16:20 2008 -0800
- removed uses of vector in favor of array in a few places
- fixed make.bash
R=r
DELTA=21 (1 added, 3 deleted, 17 changed)
OCL=19624
CL=19629
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/bef9b1713a83f5d1722a2b01a73f2a6600fda43b
元コミット内容
- removed uses of vector in favor of array in a few places
- fixed make.bash
変更の背景
このコミットは、Go言語の非常に初期の段階(2008年11月)に行われたもので、言語のコアライブラリの設計がまだ流動的であった時期のものです。コミットメッセージにある「vector
の使用を廃止し、array
に移行した」という記述は、Go言語が動的な配列のようなデータ構造をどのように扱うかについて、初期の試行錯誤があったことを示唆しています。
Go言語の最終的な設計では、C++のstd::vector
のような専用の「vector」型は導入されず、代わりに「スライス(slice)」という組み込み型が動的な配列の機能を提供することになりました。スライスは、固定長配列(array)の上に構築された軽量なデータ構造であり、配列の一部を「ビュー」として参照する形で機能します。このコミットは、おそらくGo言語がスライスという概念に落ち着く前の、vector
という名称の実験的なデータ構造から、より基本的なarray
(そして将来的にはスライス)へと設計思想が移行していく過程の一部であったと考えられます。
make.bash
の修正は、container/array
パッケージがビルドプロセスに正しく含まれるようにするためのものであり、vector
パッケージが不要になったことと関連しています。
前提知識の解説
Go言語における配列(Array)とスライス(Slice)
Go言語において、**配列(Array)**は固定長で、同じ型の要素を連続して格納するデータ構造です。配列のサイズは型の一部であり、例えば[5]int
と[10]int
は異なる型として扱われます。配列は値型であり、関数に渡される際には配列全体のコピーが作成されます。
一方、**スライス(Slice)**はGo言語における動的な配列の概念を提供します。スライスは、内部的には既存の配列を参照する「ビュー」として機能します。スライス自体は、基盤となる配列へのポインタ、スライスの長さ(現在含まれる要素数)、および容量(基盤配列がスライスの開始点から保持できる最大要素数)の3つのコンポーネントから構成されます。スライスはappend
関数などによって動的にサイズを変更でき、必要に応じてより大きな基盤配列が自動的に割り当てられ、要素がコピーされます。
このコミットが行われた時期は、Go言語がまだvector
という概念を試していた段階であり、現在のスライスが確立される前の過渡期であったと推測されます。
vector
パッケージ(初期Go言語における)
このコミットで言及されているvector
パッケージは、現在のGo標準ライブラリには存在しません。これは、Go言語の初期開発において、動的なコレクションを扱うための実験的なデータ構造として存在していたものと考えられます。C++のstd::vector
のように、要素の追加や削除によってサイズが動的に変化する機能を提供していた可能性があります。しかし、Go言語の設計思想が固まるにつれて、このvector
パッケージは廃止され、よりGoらしいスライスという概念に置き換えられていきました。
技術的詳細
このコミットの主要な変更点は、src/lib/regexp/regexp.go
とtest/vectors.go
の2つのGoソースファイルにおいて、vector
パッケージのインポートと使用をarray
パッケージに置き換えていることです。
src/lib/regexp/regexp.go
の変更
正規表現エンジンを実装しているregexp.go
ファイルでは、以下の変更が行われています。
-
インポートの変更:
import ("vector";)
がimport ("array";)
に変更されています。これにより、regexp
パッケージがvector
ではなくarray
の機能を利用するようになります。 -
RE
構造体のinst
フィールド: 正規表現の命令(instruction)を格納するRE
構造体のinst
フィールドの型が*vector.Vector
から*array.Array
に変更されています。 初期化時もre.inst = vector.New();
がre.inst = array.New(0);
に変更されています。 命令の追加メソッドAdd
では、re.inst.Append(i);
がre.inst.Push(i);
に変更されています。これは、vector
のAppend
メソッドがarray
のPush
メソッドに相当することを示唆しています。 -
CharClass
構造体のranges
フィールド: 文字クラス(CharClass
)の範囲を格納するranges
フィールドの型が*vector.Vector
から*array.IntArray
に変更されています。IntArray
はarray
パッケージ内の整数専用の配列型であったと考えられます。 初期化時もc.ranges = vector.New();
がc.ranges = array.NewIntArray(0);
に変更されています。 範囲の追加メソッドAddRange
では、cclass.ranges.Append(a);
とcclass.ranges.Append(b);
がcclass.ranges.Push(a);
とcclass.ranges.Push(b);
に変更されています。 要素へのアクセスもcclass.ranges.At(i).(int);
がcclass.ranges.At(i);
に変更されています。これは、array.IntArray
が型アサーションなしで直接整数を返すようになったことを示しています。
test/vectors.go
の変更
テストファイルであるvectors.go
では、vector
パッケージのインポートと使用がarray
パッケージに置き換えられています。
-
インポートの変更:
import vector "vector"
がimport "array"
に変更されています。 -
テスト関数
test0()
とtest1()
:v := vector.New();
がv := array.New(0);
に変更されています。v.Insert(0, a[i]);
の行は変更されていませんが、これはarray
パッケージにもInsert
メソッドが存在したか、あるいはこのテストがInsert
の動作を検証するものではなかったため、変更が不要だった可能性があります。
src/lib/make.bash
の変更
ビルドスクリプトであるmake.bash
では、以下の変更が行われています。
-
builddirs
関数の変更: ディレクトリをビルドするbuilddirs
関数内で、cd $i; make install; cd ..
という形式でサブディレクトリに移動してmake install
を実行していた部分が、(cd $i; make install)
というサブシェルで実行する形式に変更されています。これにより、現在のシェル環境のディレクトリが変更されずに済み、スクリプトの堅牢性が向上します。 -
container/array
の追加と削除:builddirs
の呼び出しリストにcontainer/array
が追加され、その後、リストの末尾からcontainer/array
が削除されています。これは、container/array
がビルド対象のライブラリとして一時的に追加されたものの、最終的にはregexp
パッケージが直接array
パッケージを参照する形になったため、container/array
という独立したビルド対象としては不要になったことを示唆しています。あるいは、container/array
がarray
パッケージの内部的なパスであった可能性もあります。
コアとなるコードの変更箇所
src/lib/make.bash
--- a/src/lib/make.bash
+++ b/src/lib/make.bash
@@ -18,9 +18,7 @@ function builddirs() {
for i
do
echo; echo; echo %%%% making lib/$i %%%%; echo
- cd $i
- make install
- cd ..
+ (cd $i; make install)
done
}
@@ -35,6 +33,7 @@ builddirs syscall\
math\
os\
strconv\
+ container/array\
reflect\
buildfiles io.go
@@ -54,4 +53,3 @@ builddirs net\
time\
http\
regexp\
-- container/array\
src/lib/regexp/regexp.go
--- a/src/lib/regexp/regexp.go
+++ b/src/lib/regexp/regexp.go
@@ -8,7 +8,7 @@ package regexp
import (
"os";
- "vector";
+ "array";
)
export var debug = false;
@@ -50,7 +50,7 @@ type RE struct {
expr string; // the original expression
ch *chan<- *RE; // reply channel when we're done
error *os.Error; // compile- or run-time error; nil if OK
- inst *vector.Vector;
+ inst *array.Array;
start Inst;
nbra int; // number of brackets in expression, for subexpressions
}
@@ -123,8 +123,8 @@ type CharClass struct {
Common;
char int;
negate bool; // is character class negated? ([^a-z])
- // Vector of int, stored pairwise: [a-z] is (a,z); x is (x,x):
- ranges *vector.Vector;
+ // array of int, stored pairwise: [a-z] is (a,z); x is (x,x):
+ ranges *array.IntArray;
}
func (cclass *CharClass) Type() int { return CHARCLASS }
@@ -135,8 +135,8 @@ func (cclass *CharClass) Print() {
print(" (negated)");
}
for i := 0; i < cclass.ranges.Len(); i += 2 {
- l := cclass.ranges.At(i).(int);
- r := cclass.ranges.At(i+1).(int);
+ l := cclass.ranges.At(i);
+ r := cclass.ranges.At(i+1);
if l == r {
print(" [", string(l), "]");
} else {
@@ -147,14 +147,14 @@ func (cclass *CharClass) AddRange(a, b int) {
func (cclass *CharClass) AddRange(a, b int) {
// range is a through b inclusive
- cclass.ranges.Append(a);
- cclass.ranges.Append(b);
+ cclass.ranges.Push(a);
+ cclass.ranges.Push(b);
}
func (cclass *CharClass) Matches(c int) bool {
for i := 0; i < cclass.ranges.Len(); i = i+2 {
- min := cclass.ranges.At(i).(int);
- max := cclass.ranges.At(i+1).(int);
+ min := cclass.ranges.At(i);
+ max := cclass.ranges.At(i+1);
if min <= c && c <= max {
return !cclass.negate
}
@@ -164,7 +164,7 @@ func (cclass *CharClass) Matches(c int) bool {
func NewCharClass() *CharClass {
c := new(CharClass);
- c.ranges = vector.New();
+ c.ranges = array.NewIntArray(0);
return c;
}
@@ -220,7 +220,7 @@ func (re *RE) Error(err *os.Error) {
func (re *RE) Add(i Inst) Inst {
i.SetIndex(re.inst.Len());
- re.inst.Append(i);
+ re.inst.Push(i);
return i;
}
@@ -574,7 +574,7 @@ func (re *RE) DoParse() {
func Compiler(str string, ch *chan *RE) {
re := new(RE);
re.expr = str;
- re.inst = vector.New();
+ re.inst = array.New(0);
re.ch = ch;
re.DoParse();
ch <- re;
test/vectors.go
--- a/test/vectors.go
+++ b/test/vectors.go
@@ -6,7 +6,7 @@
package main
-import vector "vector"
+import "array"
type S struct {
@@ -21,7 +21,7 @@ func (p *S) Init(val int) *S {
func test0() {
- v := vector.New();
+ v := array.New(0);
if v.Len() != 0 {
panic("len = ", v.Len(), "\n");
}
@@ -34,7 +34,7 @@ func test1() {
\ta[i] = new(S).Init(i);\
}\
-\tv := vector.New();
+\tv := array.New(0);\
for i := 0; i < len(a); i++ {
v.Insert(0, a[i]);
if v.Len() != i + 1 {
コアとなるコードの解説
このコミットの核となる変更は、Go言語の正規表現エンジン(regexp
パッケージ)が内部で利用する動的なデータ構造を、vector
からarray
へと切り替えた点にあります。
regexp.go
ファイルは、正規表現のパース、コンパイル、実行に関わるロジックを実装しています。この中で、正規表現の命令列を格納するRE
構造体のinst
フィールドや、文字クラスの範囲を格納するCharClass
構造体のranges
フィールドが、動的に要素を追加・参照する必要があるデータ構造として使われていました。
変更前は、これらのフィールドは*vector.Vector
型でした。vector.New()
で新しいvector
インスタンスを作成し、vector.Append()
で要素を追加し、vector.At()
で要素にアクセスしていました。
変更後は、*array.Array
型(または*array.IntArray
型)に切り替わっています。これに伴い、インスタンスの作成はarray.New(0)
やarray.NewIntArray(0)
に、要素の追加はarray.Push()
に、要素へのアクセスはarray.At()
に変更されています。特にCharClass.ranges
のAt
メソッドの呼び出しでは、型アサーション(int)
が不要になっていることから、array.IntArray
がより型安全な整数専用の配列として設計されていたことが伺えます。
この変更は、Go言語の初期設計におけるデータ構造の選択と進化を示しています。vector
という概念が、よりGo言語の哲学に合致するarray
(そして最終的にはスライス)へと洗練されていく過程の一端を垣間見ることができます。array
パッケージが提供する機能は、後のスライスの基盤となる固定長配列の概念に近いものであったと考えられます。
make.bash
の変更は、このデータ構造の変更に伴うビルドシステムの調整です。サブシェルでのmake install
実行は、ビルドスクリプトの実行環境をクリーンに保つための一般的な改善であり、このコミットの主要な目的であるvector
からarray
への移行をサポートするものです。
関連リンク
参考にした情報源リンク
- Go言語における配列とスライスに関するドキュメントや解説記事
- Go言語の初期開発に関する情報(一般的なGo言語の歴史や設計思想に関する記事)
- Go言語の
container/array
パッケージに関する情報(もし存在すれば)- (現在のGo標準ライブラリには
container/array
というパッケージは存在しないため、このコミット時点での初期の実験的なパッケージであった可能性が高い)
- (現在のGo標準ライブラリには
- Go言語の
regexp
パッケージに関する情報