Go 言語仕様の簡単なまとめ 3

構造体

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);
    }()
}