[インデックス 1673] ファイルの概要
このコミットは、Go言語の標準ライブラリにvector
パッケージを導入し、既存のarray
パッケージを非推奨にする変更を含んでいます。vector
パッケージは、動的な配列(ベクター)の機能を提供し、ジェネリックなElement
インターフェースと、特定の型(この場合はint
)に特化したIntVector
を提供します。
コミット
commit 127526649f68b8fc8ea1ab041d6a01c0fd23b7e0
Author: Robert Griesemer <gri@golang.org>
Date: Fri Feb 13 15:07:56 2009 -0800
- vector package (identical to array except for names)
- updated some file (but not all - left array package in place for now)
R=rsc
DELTA=530 (483 added, 0 deleted, 47 changed)
OCL=25025
CL=25025
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/127526649f68b8fc8ea1ab041d6a01c0fd23b7e0
元コミット内容
このコミットの元の内容は以下の通りです。
vector
パッケージの導入(名前を除いてarray
パッケージと同一)。- 一部のファイルが更新された(ただし、全てではなく、
array
パッケージは当面残された)。
変更の背景
このコミットが行われた2009年2月は、Go言語がまだ一般に公開される前の初期開発段階にありました。Go言語の設計思想の一つに「シンプルさ」と「実用性」があり、標準ライブラリの設計もその原則に従っていました。
初期のGo言語には、動的なコレクションを扱うためのarray
パッケージが存在していましたが、その命名やインターフェースが、より一般的な「ベクター」という概念に合致するように見直されたと考えられます。array
という名前は、固定長配列を想起させる可能性があり、動的な要素の追加・削除が可能なデータ構造にはvector
という名前の方が適切であるという判断があったと推測されます。
また、Go言語の初期にはジェネリクス(総称型)が導入されていなかったため、様々な型の要素を扱えるようにするためにinterface{}
(空インターフェース)を使用し、特定の型に特化した実装(例: IntVector
)を別途提供するというパターンが採用されていました。これは、ジェネリクスがないGo言語で汎用的なデータ構造を実装するための一般的なアプローチでした。
この変更は、Go言語の標準ライブラリにおけるデータ構造の命名規則と設計の一貫性を向上させるための初期の取り組みの一環であると言えます。
前提知識の解説
Go言語の初期の型システムとジェネリクス
Go言語は、その設計当初からシンプルさを重視しており、C++やJavaのような複雑なジェネリクス(総称型)は採用していませんでした。そのため、様々な型のデータを格納できる汎用的なコンテナ(リスト、マップなど)を実装する際には、interface{}
型が用いられました。interface{}
はGo言語における任意の型を表すことができ、これにより異なる型の値を一つのコレクションに格納することが可能になります。
しかし、interface{}
を使用すると、コレクションから値を取り出す際に型アサーション(例: value.(int)
)が必要となり、実行時エラーのリスクや、型安全性の低下、パフォーマンスのオーバーヘッドが発生する可能性があります。このため、特定のプリミティブ型(例: int
, string
)に特化したコンテナが必要な場合には、その型専用のコンテナを別途実装するというパターンがよく見られました。このコミットで導入されるIntVector
はその典型例です。
動的配列(ベクター)の概念
動的配列(またはベクター)は、要素の追加や削除によってサイズが動的に変化する配列のようなデータ構造です。内部的には固定長配列で実装されることが多く、容量が不足した場合にはより大きな新しい配列を確保し、既存の要素をコピーするという操作が行われます。これにより、プログラマは固定長配列のサイズ管理を意識することなく、柔軟に要素を扱えます。
Go言語のMakefile
Go言語の初期のビルドシステムは、現在のようなgo build
コマンドが主流になる前は、Makefile
が広く使われていました。このコミットでもsrc/lib/container/Makefile
が追加されており、vector
パッケージのビルド、テスト、インストールに関するルールが定義されています。
GC
,CC
,AS
,AR
: Goコンパイラ、Cコンパイラ、アセンブラ、アーカイバを指します。packages
:vector.a
(アーカイブファイル)をビルドするターゲット。install
: ビルドされたvector.a
を$(GOROOT)/pkg/vector.a
にコピーするターゲット。
技術的詳細
このコミットの主要な技術的変更点は、array
パッケージからvector
パッケージへの移行です。
vector
パッケージの設計
src/lib/container/vector.go
で定義されているvector
パッケージは、以下の主要な要素で構成されています。
Element interface {}
: 任意の型の要素を格納するためのインターフェース。Go言語にジェネリクスがなかったため、この型が汎用的な要素型として使用されます。Vector struct { a []Element }
:vector
の基盤となる構造体で、内部的にはElement
型のスライスa
を保持します。Init(initial_len int) *Vector
:Vector
を初期化するメソッド。指定された初期長で内部スライスを準備します。容量が不足する場合は、既存の容量の2倍に拡張するか、必要な長さに合わせて拡張します。New(len int) *Vector
:Vector
の新しいインスタンスを作成し、初期化するコンビニエンス関数。Len() int
:Vector
の現在の要素数を返します。At(i int) Element
: 指定されたインデックスi
の要素を返します。Set(i int, x Element)
: 指定されたインデックスi
に要素x
を設定します。Last() Element
:Vector
の最後の要素を返します。Insert(i int, x Element)
: 指定されたインデックスi
に要素x
を挿入します。内部的にはexpand
関数を呼び出してスライスの容量を調整し、要素を移動させます。Delete(i int) Element
: 指定されたインデックスi
の要素を削除します。要素を削除した後、スライスを縮小し、GCのために削除された要素の参照をnil
にします。InsertVector(i int, x *Vector)
: 別のVector
の全要素を指定されたインデックスに挿入します。Cut(i, j int)
: インデックスi
からj-1
までの要素を削除します。Slice(i, j int) *Vector
: インデックスi
からj-1
までの要素を含む新しいVector
を返します。Do(f func(elem Element))
:Vector
の各要素に対して指定された関数f
を実行します。Push(x Element)
:Vector
の末尾に要素を追加します(Insert
のラッパー)。Pop() Element
:Vector
の末尾から要素を削除し、返します(Delete
のラッパー)。AppendVector(x *Vector)
: 別のVector
の全要素を現在のVector
の末尾に追加します。Less(i, j int) bool
:sort.Sort
インターフェースの一部として、インデックスi
の要素がインデックスj
の要素より小さいかどうかを比較します。このメソッドはLessInterface
というカスタムインターフェースに依存しています。Swap(i, j int)
:sort.Sort
インターフェースの一部として、インデックスi
とj
の要素を交換します。
IntVector
パッケージの設計
src/lib/container/intvector.go
で定義されているIntVector
は、vector.Vector
を埋め込み(composition)によって拡張し、int
型に特化したメソッドを提供します。これにより、型アサーションの記述を減らし、より型安全な操作を可能にしています。
type IntVector struct { vector.Vector; }
:vector.Vector
を匿名フィールドとして埋め込んでいます。これにより、IntVector
のインスタンスはvector.Vector
のすべてのメソッドを直接呼び出すことができます。Init(len int) *IntVector
:vector.Vector
のInit
メソッドを呼び出し、IntVector
自身を返します。NewIntVector(len int) *IntVector
:IntVector
の新しいインスタンスを作成し、初期化するコンビニエンス関数。At(i int) int
:vector.Vector.At(i)
の結果をint
型に型アサーションして返します。Set(i int, x int)
:vector.Vector.Set(i, x)
を呼び出します。Last() int
:vector.Vector.Last()
の結果をint
型に型アサーションして返します。Insert(i int, x int)
:vector.Vector.Insert(i, x)
を呼び出します。Delete(i int) int
:vector.Vector.Delete(i)
の結果をint
型に型アサーションして返します。Push(x int)
:vector.Vector.Push(x)
を呼び出します。Pop() int
:vector.Vector.Pop()
の結果をint
型に型アサーションして返します。Less(i, j int) bool
:sort.Sort
インターフェースの一部として、int
型の要素を直接比較します。
array
パッケージの非推奨化
src/lib/container/array/array.go
とsrc/lib/container/array/intarray.go
には、以下のコメントが追加され、array
パッケージが非推奨であることが明示されています。
//
// *** DEPRECATED PACKAGE - USE package vector INSTEAD ***
//
これは、将来的にarray
パッケージが削除されるか、あるいはvector
パッケージに完全に置き換えられることを示唆しています。
既存コードの更新
tabwriter
, test/vectors.go
, usr/gri/pretty/ast.go
, usr/gri/pretty/compilation.go
, usr/gri/pretty/parser.go
, usr/gri/pretty/printer.go
, usr/gri/pretty/symboltable.go
など、既存の複数のファイルでarray
パッケージへの参照がvector
パッケージへの参照に置き換えられています。これは、新しいvector
パッケージへの移行が既に始まっていることを示しています。
特に、tabwriter
パッケージでは、内部で使用していたarray.Array
やarray.IntArray
がvector.Vector
やvector.IntVector
に置き換えられています。
コアとなるコードの変更箇所
このコミットのコアとなるコードの変更は、主に以下のファイルに集中しています。
src/lib/container/Makefile
:vector
パッケージのビルド設定が追加されました。src/lib/container/intvector.go
:IntVector
構造体とそのメソッドが新規追加されました。src/lib/container/vector.go
:Vector
構造体とそのメソッドが新規追加されました。src/lib/container/vector_test.go
:vector
パッケージのテストコードが新規追加されました。src/lib/container/array/array.go
:array
パッケージが非推奨であることを示すコメントが追加されました。src/lib/container/array/intarray.go
:intarray
パッケージが非推奨であることを示すコメントが追加されました。src/lib/tabwriter/tabwriter.go
:array
パッケージからvector
パッケージへの依存関係が変更されました。test/vectors.go
:array
パッケージからvector
パッケージへの依存関係が変更されました。usr/gri/pretty/*.go
:array
パッケージからvector
パッケージへの依存関係が変更されました。
コアとなるコードの解説
src/lib/container/vector.go
このファイルは、Go言語における汎用的な動的配列であるVector
の基盤を定義しています。
package vector
type (
Element interface {}; // 任意の型を格納するためのインターフェース
Vector struct {
a []Element // 内部的にはElement型のスライスを保持
}
)
// 要素をコピーするヘルパー関数
func copy(dst, src []Element) {
for i := 0; i < len(src); i++ {
dst[i] = src[i]
}
}
// n個の要素を位置iに挿入するためにスライスを拡張する
func expand(a []Element, i, n int) []Element {
len0 := len(a);
len1 := len0 + n;
if len1 < cap(a) {
// 十分な容量がある場合、スライスを拡張する
a = a[0 : len1]
} else {
// 容量が不足する場合、容量を倍にするか、必要な長さに拡張する
capb := cap(a)*2;
if capb < len1 {
capb = len1
}
b := make([]Element, len1, capb);
copy(b, a); // 既存の要素を新しいスライスにコピー
a = b
}
// 挿入位置に穴を開けるために要素を移動
for j := len0-1; j >= i ; j-- {
a[j+n] = a[j]
}
return a
}
// Vectorを初期化する
func (p *Vector) Init(initial_len int) *Vector {
a := p.a;
if cap(a) == 0 || cap(a) < initial_len {
n := 8; // 初期容量
if initial_len > n {
n = initial_len
}
a = make([]Element, n);
} else {
// 既存のエントリをnilにする(GCを助けるため)
for j := len(a) - 1; j >= 0; j-- {
a[j] = nil
}
}
p.a = a[0 : initial_len];
return p
}
// 新しいVectorを作成する
func New(len int) *Vector {
return new(Vector).Init(len)
}
// ... その他のメソッド(Len, At, Set, Last, Insert, Delete, Cut, Slice, Do, Push, Pop, AppendVector, Less, Swap)
expand
関数は、Vector
の動的なサイズ変更の核心部分です。要素を挿入する際に、内部スライスの容量が足りなければ、新しいより大きなスライスを作成し、既存の要素をコピーします。その後、挿入位置に「穴」を開けるために、既存の要素を後方に移動させます。
src/lib/container/intvector.go
このファイルは、vector.Vector
を基盤として、int
型に特化したIntVector
を実装しています。
package vector
import "vector" // 同じパッケージ名だが、これはvector.goで定義されたvectorパッケージを指す
type IntVector struct {
// TODO do not export field
vector.Vector; // vector.Vectorを埋め込み
}
// IntVectorを初期化する
func (p *IntVector) Init(len int) *IntVector {
p.Vector.Init(len); // 基盤のVectorのInitを呼び出す
return p;
}
// 新しいIntVectorを作成する
func NewIntVector(len int) *IntVector {
return new(IntVector).Init(len)
}
// 指定されたインデックスのint要素を返す
func (p *IntVector) At(i int) int {
return p.Vector.At(i).(int) // 型アサーション
}
// 指定されたインデックスにint要素を設定する
func (p *IntVector) Set(i int, x int) {
p.Vector.Set(i, x)
}
// ... その他のint型に特化したメソッド(Last, Insert, Delete, Push, Pop, Less)
IntVector
はvector.Vector
を埋め込むことで、vector.Vector
のすべてのメソッドを自動的に継承します。そして、At
, Set
, Push
, Pop
などのメソッドをint
型に特化して再定義することで、利用者が型アサーションを明示的に記述する必要がなくなります。これは、ジェネリクスがないGo言語で型安全性を高めるための一般的なパターンでした。
関連リンク
- Go言語の公式ドキュメント (当時のバージョンに該当するものは見つけにくい可能性がありますが、現在の
container/list
やcontainer/ring
パッケージのドキュメントが参考になるかもしれません) - Go言語の初期の設計に関する議論やメーリングリストのアーカイブ (Go言語の歴史的背景を理解する上で有用)
参考にした情報源リンク
- Go言語のGitHubリポジトリ: https://github.com/golang/go
- Go言語の初期のコミットログ
- Go言語の設計に関するブログ記事や論文 (特にジェネリクスに関する初期の議論)
- Go言語の
interface{}
型と型アサーションに関する一般的な解説 - 動的配列(ベクター)のデータ構造に関する一般的な情報
[インデックス 1673] ファイルの概要
このコミットは、Go言語の標準ライブラリにvector
パッケージを導入し、既存のarray
パッケージを非推奨にする変更を含んでいます。vector
パッケージは、動的な配列(ベクター)の機能を提供し、ジェネリックなElement
インターフェースと、特定の型(この場合はint
)に特化したIntVector
を提供します。
コミット
commit 127526649f68b8fc8ea1ab041d6a01c0fd23b7e0
Author: Robert Griesemer <gri@golang.org>
Date: Fri Feb 13 15:07:56 2009 -0800
- vector package (identical to array except for names)
- updated some file (but not all - left array package in place for now)
R=rsc
DELTA=530 (483 added, 0 deleted, 47 changed)
OCL=25025
CL=25025
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/127526649f68b8fc8ea1ab041d6a01c0fd23b7e0
元コミット内容
このコミットの元の内容は以下の通りです。
vector
パッケージの導入(名前を除いてarray
パッケージと同一)。- 一部のファイルが更新された(ただし、全てではなく、
array
パッケージは当面残された)。
変更の背景
このコミットが行われた2009年2月は、Go言語がまだ一般に公開される前の初期開発段階にありました。Go言語の設計思想の一つに「シンプルさ」と「実用性」があり、標準ライブラリの設計もその原則に従っていました。
初期のGo言語には、動的なコレクションを扱うためのarray
パッケージが存在していましたが、その命名やインターフェースが、より一般的な「ベクター」という概念に合致するように見直されたと考えられます。array
という名前は、固定長配列を想起させる可能性があり、動的な要素の追加・削除が可能なデータ構造にはvector
という名前の方が適切であるという判断があったと推測されます。
また、Go言語の初期にはジェネリクス(総称型)が導入されていなかったため、様々な型の要素を扱えるようにするためにinterface{}
(空インターフェース)を使用し、特定の型(この場合はint
)に特化した実装(例: IntVector
)を別途提供するというパターンが採用されていました。これは、ジェネリクスがないGo言語で汎用的なデータ構造を実装するための一般的なアプローチでした。
この変更は、Go言語の標準ライブラリにおけるデータ構造の命名規則と設計の一貫性を向上させるための初期の取り組みの一環であると言えます。
前提知識の解説
Go言語の初期の型システムとジェネリクス
Go言語は、その設計当初からシンプルさを重視しており、C++やJavaのような複雑なジェネリクス(総称型)は採用していませんでした。そのため、様々な型のデータを格納できる汎用的なコンテナ(リスト、マップなど)を実装する際には、interface{}
型が用いられました。interface{}
はGo言語における任意の型を表すことができ、これにより異なる型の値を一つのコレクションに格納することが可能になります。
しかし、interface{}
を使用すると、コレクションから値を取り出す際に型アサーション(例: value.(int)
)が必要となり、実行時エラーのリスクや、型安全性の低下、パフォーマンスのオーバーヘッドが発生する可能性があります。このため、特定のプリミティブ型(例: int
, string
)に特化したコンテナが必要な場合には、その型専用のコンテナを別途実装するというパターンがよく見られました。このコミットで導入されるIntVector
はその典型例です。
動的配列(ベクター)の概念
動的配列(またはベクター)は、要素の追加や削除によってサイズが動的に変化する配列のようなデータ構造です。内部的には固定長配列で実装されることが多く、容量が不足した場合にはより大きな新しい配列を確保し、既存の要素をコピーするという操作が行われます。これにより、プログラマは固定長配列のサイズ管理を意識することなく、柔軟に要素を扱えます。
Go言語のMakefile
Go言語の初期のビルドシステムは、現在のようなgo build
コマンドが主流になる前は、Makefile
が広く使われていました。このコミットでもsrc/lib/container/Makefile
が追加されており、vector
パッケージのビルド、テスト、インストールに関するルールが定義されています。
GC
,CC
,AS
,AR
: Goコンパイラ、Cコンパイラ、アセンブラ、アーカイバを指します。packages
:vector.a
(アーカイブファイル)をビルドするターゲット。install
: ビルドされたvector.a
を$(GOROOT)/pkg/vector.a
にコピーするターゲット。
技術的詳細
このコミットの主要な技術的変更点は、array
パッケージからvector
パッケージへの移行です。
vector
パッケージの設計
src/lib/container/vector.go
で定義されているvector
パッケージは、以下の主要な要素で構成されています。
Element interface {}
: 任意の型の要素を格納するためのインターフェース。Go言語にジェネリクスがなかったため、この型が汎用的な要素型として使用されます。Vector struct { a []Element }
:vector
の基盤となる構造体で、内部的にはElement
型のスライスa
を保持します。Init(initial_len int) *Vector
:Vector
を初期化するメソッド。指定された初期長で内部スライスを準備します。容量が不足する場合は、既存の容量の2倍に拡張するか、必要な長さに合わせて拡張します。New(len int) *Vector
:Vector
の新しいインスタンスを作成し、初期化するコンビニエンス関数。Len() int
:Vector
の現在の要素数を返します。At(i int) Element
: 指定されたインデックスi
の要素を返します。Set(i int, x Element)
: 指定されたインデックスi
に要素x
を設定します。Last() Element
:Vector
の最後の要素を返します。Insert(i int, x Element)
: 指定されたインデックスi
に要素x
を挿入します。内部的にはexpand
関数を呼び出してスライスの容量を調整し、要素を移動させます。Delete(i int) Element
: 指定されたインデックスi
の要素を削除します。要素を削除した後、スライスを縮小し、GCのために削除された要素の参照をnil
にします。InsertVector(i int, x *Vector)
: 別のVector
の全要素を指定されたインデックスに挿入します。Cut(i, j int)
: インデックスi
からj-1
までの要素を削除します。Slice(i, j int) *Vector
: インデックスi
からj-1
までの要素を含む新しいVector
を返します。Do(f func(elem Element))
:Vector
の各要素に対して指定された関数f
を実行します。Push(x Element)
:Vector
の末尾に要素を追加します(Insert
のラッパー)。Pop() Element
:Vector
の末尾から要素を削除し、返します(Delete
のラッパー)。AppendVector(x *Vector)
: 別のVector
の全要素を現在のVector
の末尾に追加します。Less(i, j int) bool
:sort.Sort
インターフェースの一部として、インデックスi
の要素がインデックスj
の要素より小さいかどうかを比較します。このメソッドはLessInterface
というカスタムインターフェースに依存しています。Swap(i, j int)
:sort.Sort
インターフェースの一部として、インデックスi
とj
の要素を交換します。
IntVector
パッケージの設計
src/lib/container/intvector.go
で定義されているIntVector
は、vector.Vector
を埋め込み(composition)によって拡張し、int
型に特化したメソッドを提供します。これにより、型アサーションの記述を減らし、より型安全な操作を可能にしています。
type IntVector struct { vector.Vector; }
:vector.Vector
を匿名フィールドとして埋め込んでいます。これにより、IntVector
のインスタンスはvector.Vector
のすべてのメソッドを直接呼び出すことができます。Init(len int) *IntVector
:vector.Vector
のInit
メソッドを呼び出し、IntVector
自身を返します。NewIntVector(len int) *IntVector
:IntVector
の新しいインスタンスを作成し、初期化するコンビニエンス関数。At(i int) int
:vector.Vector.At(i)
の結果をint
型に型アサーションして返します。Set(i int, x int)
:vector.Vector.Set(i, x)
を呼び出します。Last() int
:vector.Vector.Last()
の結果をint
型に型アサーションして返します。Insert(i int, x int)
:vector.Vector.Insert(i, x)
を呼び出します。Delete(i int) int
:vector.Vector.Delete(i)
の結果をint
型に型アサーションして返します。Push(x int)
:vector.Vector.Push(x)
を呼び出します。Pop() int
:vector.Vector.Pop()
の結果をint
型に型アサーションして返します。Less(i, j int) bool
:sort.Sort
インターフェースの一部として、int
型の要素を直接比較します。
array
パッケージの非推奨化
src/lib/container/array/array.go
とsrc/lib/container/array/intarray.go
には、以下のコメントが追加され、array
パッケージが非推奨であることが明示されています。
//
// *** DEPRECATED PACKAGE - USE package vector INSTEAD ***
//
これは、将来的にarray
パッケージが削除されるか、あるいはvector
パッケージに完全に置き換えられることを示唆しています。
既存コードの更新
tabwriter
, test/vectors.go
, usr/gri/pretty/ast.go
, usr/gri/pretty/compilation.go
, usr/gri/pretty/parser.go
, usr/gri/pretty/printer.go
, usr/gri/pretty/symboltable.go
など、既存の複数のファイルでarray
パッケージへの参照がvector
パッケージへの参照に置き換えられています。これは、新しいvector
パッケージへの移行が既に始まっていることを示しています。
特に、tabwriter
パッケージでは、内部で使用していたarray.Array
やarray.IntArray
がvector.Vector
やvector.IntVector
に置き換えられています。
コアとなるコードの変更箇所
このコミットのコアとなるコードの変更は、主に以下のファイルに集中しています。
src/lib/container/Makefile
:vector
パッケージのビルド設定が追加されました。src/lib/container/intvector.go
:IntVector
構造体とそのメソッドが新規追加されました。src/lib/container/vector.go
:Vector
構造体とそのメソッドが新規追加されました。src/lib/container/vector_test.go
:vector
パッケージのテストコードが新規追加されました。src/lib/container/array/array.go
:array
パッケージが非推奨であることを示すコメントが追加されました。src/lib/container/array/intarray.go
:intarray
パッケージが非推奨であることを示すコメントが追加されました。src/lib/tabwriter/tabwriter.go
:array
パッケージからvector
パッケージへの依存関係が変更されました。test/vectors.go
:array
パッケージからvector
パッケージへの依存関係が変更されました。usr/gri/pretty/*.go
:array
パッケージからvector
パッケージへの依存関係が変更されました。
コアとなるコードの解説
src/lib/container/vector.go
このファイルは、Go言語における汎用的な動的配列であるVector
の基盤を定義しています。
package vector
type (
Element interface {}; // 任意の型を格納するためのインターフェース
Vector struct {
a []Element // 内部的にはElement型のスライスを保持
}
)
// 要素をコピーするヘルパー関数
func copy(dst, src []Element) {
for i := 0; i < len(src); i++ {
dst[i] = src[i]
}
}
// n個の要素を位置iに挿入するためにスライスを拡張する
func expand(a []Element, i, n int) []Element {
len0 := len(a);
len1 := len0 + n;
if len1 < cap(a) {
// 十分な容量がある場合、スライスを拡張する
a = a[0 : len1]
} else {
// 容量が不足する場合、容量を倍にするか、必要な長さに拡張する
capb := cap(a)*2;
if capb < len1 {
capb = len1
}
b := make([]Element, len1, capb);
copy(b, a); // 既存の要素を新しいスライスにコピー
a = b
}
// 挿入位置に穴を開けるために要素を移動
for j := len0-1; j >= i ; j-- {
a[j+n] = a[j]
}
return a
}
// Vectorを初期化する
func (p *Vector) Init(initial_len int) *Vector {
a := p.a;
if cap(a) == 0 || cap(a) < initial_len {
n := 8; // 初期容量
if initial_len > n {
n = initial_len
}
a = make([]Element, n);
} else {
// 既存のエントリをnilにする(GCを助けるため)
for j := len(a) - 1; j >= 0; j-- {
a[j] = nil
}
}
p.a = a[0 : initial_len];
return p
}
// 新しいVectorを作成する
func New(len int) *Vector {
return new(Vector).Init(len)
}
// ... その他のメソッド(Len, At, Set, Last, Insert, Delete, Cut, Slice, Do, Push, Pop, AppendVector, Less, Swap)
expand
関数は、Vector
の動的なサイズ変更の核心部分です。要素を挿入する際に、内部スライスの容量が足りなければ、新しいより大きなスライスを作成し、既存の要素をコピーします。その後、挿入位置に「穴」を開けるために、既存の要素を後方に移動させます。
src/lib/container/intvector.go
このファイルは、vector.Vector
を基盤として、int
型に特化したIntVector
を実装しています。
package vector
import "vector" // 同じパッケージ名だが、これはvector.goで定義されたvectorパッケージを指す
type IntVector struct {
// TODO do not export field
vector.Vector; // vector.Vectorを埋め込み
}
// IntVectorを初期化する
func (p *IntVector) Init(len int) *IntVector {
p.Vector.Init(len); // 基盤のVectorのInitを呼び出す
return p;
}
// 新しいIntVectorを作成する
func NewIntVector(len int) *IntVector {
return new(IntVector).Init(len)
}
// 指定されたインデックスのint要素を返す
func (p *IntVector) At(i int) int {
return p.Vector.At(i).(int) // 型アサーション
}
// 指定されたインデックスにint要素を設定する
func (p *IntVector) Set(i int, x int) {
p.Vector.Set(i, x)
}
// ... その他のint型に特化したメソッド(Last, Insert, Delete, Push, Pop, Less)
IntVector
はvector.Vector
を埋め込むことで、vector.Vector
のすべてのメソッドを自動的に継承します。そして、At
, Set
, Push
, Pop
などのメソッドをint
型に特化して再定義することで、利用者が型アサーションを明示的に記述する必要がなくなります。これは、ジェネリクスがないGo言語で型安全性を高めるための一般的なパターンでした。
関連リンク
- Go言語の公式ドキュメント (当時のバージョンに該当するものは見つけにくい可能性がありますが、現在の
container/list
やcontainer/ring
パッケージのドキュメントが参考になるかもしれません) - Go言語の初期の設計に関する議論やメーリングリストのアーカイブ (Go言語の歴史的背景を理解する上で有用)
参考にした情報源リンク
- Go言語のGitHubリポジトリ: https://github.com/golang/go
- Go言語の初期のコミットログ
- Go言語の設計に関するブログ記事や論文 (特にジェネリクスに関する初期の議論)
- Go言語の
interface{}
型と型アサーションに関する一般的な解説 - 動的配列(ベクター)のデータ構造に関する一般的な情報
- Stack Overflow: https://stackoverflow.com/questions/tagged/go (Go言語に関する一般的な質問と回答)
- Go.dev: https://go.dev/ (Go言語の公式ウェブサイト)
- Medium: https://medium.com/ (Go言語に関する技術記事)
- Ardan Labs: https://www.ardanlabs.com/ (Go言語のトレーニングとコンサルティング)
- YouTube: https://www.youtube.com/ (Go言語に関する動画コンテンツ)