構造体
type T struct { a int; c string; } t := &T{ 7, "abc" };
インターフェース
struct がデータ型を定義するのに対して interface はメソッドセットを定義する。インターフェースはメソッドの引数として指定するなど、型として利用できる。
type ReadWrite interface { Read(b Buffer) bool; Write(b Buffer) bool; }
上記は ReadWrite というインターフェースを定義している。インターフェースの実装は、ある型Tのメソッドとしてシグネチャを揃えたものを定義することで行う。
func (p T) Read(b Buffer) bool { return ... } func (p T) Write(b Buffer) bool { return ... }
これで、ある型TはReaderWriterインターフェースを実装したこととなる。
さらに、Lockインターフェースを用意してTに実装する。
type Lock interface { Lock(); Unlock(); } func (p T) Lock() { ... } func (p T) Unlock() { ... }
前述の ReadWrite と Lock インターフェースは以下のように新たなインターフェースとしてまとめることができる。
type File interface { ReadWrite; Lock; }
ある型Tは File インターフェースを実装していることになる。
newによるメモリ割り当て
Go ではメモリ割り当てに new() と make() が用意されている。
new(T)は、T型のゼロで初期化された新しい要素を割り当て、そのアドレスを*T型の値として返す。
type S struct { a int; b float } p := new(S) // pはSのインスタンスへのポインタ
newによるインスタンス化により初期値はゼロとなる。
複合リテラルを使用すると初期値を明示的に与えることができる。
p := S{1, 0};
以下のように変数名を指定することもできる。指定が無い変数に関してはゼロで初期化される。
p := S{a:1};
makeによるメモリ割り当て
スライス、マップ、チャンネル用にメモリ割り当てを行う。スライス、マップ、チャンネルは必要なデータ構造への参照を保持する型であるため、newが *T 型を返すのに対し、makeは初期化した T 型を返す。
var p *[]int = new([]int); // スライス(nil)のポインタを返却 var v []int = make([]int, 100); // 長さ100の配列を割り当て、そのスライスの参照を返却
マップ
キーがstring値がintのマップ定義(初期化含む)
var timeZone = map[string] int { "UTC": 0*60*60, "EST": -5*60*60, }
tzにはマップのキー値が格納されているものとすると、以下のイディオムが使える。
var seconds int; var ok bool; seconds, ok = timeZone[tz]
boole型のokにはマップにキーが存在しなかった場合にfalseが入り、以下のように利用できる。
if seconds, ok := timeZone[tz]; ok { return seconds }
マップからの値の削除は以下。
timeZone["PDT"] = 0, false;
並列処理
関数やメソッドをgoキーワードをつけて呼び出すことでgoルーチンと呼ばれる別スレッド内での実行となる。以下のsortはブロックせずにgoルーチンで実行され、処理の終了までブロックされることはない。
go list.Sort();
関数リテラルにてgoルーチンでの並列実行を行う例
func Announce(message string, delay int64) { go func() { time.Sleep(delay); fmt.Println(message); }() }