技術めも

study effective go

http://golang.jp/effective_go

ifとswitchには初期化ステートメントを記述できるため、そこでローカル変数の準備を行うのが一般的です。

if err := file.Chmod(0664); err != nil {
    log.Print(err)
    return err
}

newについて説明します。
これはメモリの割り当てを行う組み込み関数ですが、他言語のnewの多くとは異なり、メモリの初期化ではなく、ゼロ化のみを行います。
すなわち、new(T)は、型Tの新しいアイテム用にゼロ化した領域を割り当て、そのアドレスである*T型の値を返します。
Go言語風に言い換えると、new(T)が返す値は、新しく割り当てられた型Tのゼロ値のポインタです。

コンストラクタと複合リテラル
下の例はosパッケージからの抜粋です。この例のようにゼロ値では充分でなく、コンストラクタによる初期化が必要となることがあります。

func NewFile(fd int, name string) *File {
    if fd < 0 {
        return nil
    }
    f := new(File)
    f.fd = fd
    f.name = name
    f.dirinfo = nil
    f.nepipe = 0
    return f
}

上のコードには冗長な部分が多く見られます。複合リテラルとは、実行する度に新しいインスタンスを生成する式であり、これを使うことで下のコードのように単純化することができます。
式 new(File) と &File{} は等価です。

func NewFile(fd int, name string) *File {
    if fd < 0 {
        return nil
    }
    return &File{fd, name, nil, 0}
    // return &File{fd: fd, name: name}
}

make で割り当てできるのはスライス、マップ、チャネルだけであり、初期化された、すなわちゼロ値でないT型(*Tでない)の値を返します。
makeとnewを使い分ける理由は、これらの3つの型が隠蔽されたデータ構造への参照であり、このデータ構造が使用前に初期化されている必要があるためです。

マップから登録を削除するには、代入方向を変えて複数代入式の右側に論理値を指定してください。この論理値の値が偽のとき登録が削除されます。このときマップ内にキーが存在しなくても問題ありません。

timeZone["PDT"] = 0, false  // 標準時に

代替フォーマット %#v を使うとどんな値でも完全なGo言語の構文形式で出力されます。
%T これは値の型を出力します。

fmt.Printf("%#v\n", timeZone)
map[string] int{"CST":-21600, "PST":-28800, "EST":-18000, "UTC":0, "MST":-25200}

...パラメータには型を指定します。

func Min(a ...int) int {
    min := int(^uint(0) >> 1)  // intの最大値
    for _, i := range a {
        if i < min {
            min = i
        }
    }
    return min
}

メソッドは、特別なレシーバ( receiver )引数を関数に取ります。(t *T)

func (t *T) String() string {
    return fmt.Sprintf("%d/%g/%q", t.a, t.b, t.c)
}
fmt.Printf("%v\n", t)

変数

var (
    HOME = os.Getenv("HOME")
    USER = os.Getenv("USER")
    GOROOT = os.Getenv("GOROOT")
)

各ソースファイルにはそれぞれ必要に応じて、セットアップのためにパラメータを持たない関数initを定義することができます。
初期化処理中に実行されるスレッドは常にひとつだけです。ゴルーチンは初期化が完了するまで実行開始しません

func init() {
    if USER == "" {
        log.Fatal("$USER not set")
    }
    if HOME == "" {
        HOME = "/usr/" + USER
    }
    if GOROOT == "" {
        GOROOT = HOME + "/go"
    }
    // GOROOTはコマンドラインから--gorrotフラグを指定することで上書き可能
    flag.StringVar(&GOROOT, "goroot", GOROOT, "Go root directory")
}

メソッド

TODO

インタフェースとメソッド

// 単純なカウントサーバ
type Counter struct {
    n int
}

func (ctr *Counter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
    ctr.n++
    fmt.Fprintf(w, "counter = %d\n", ctr.n)
}
// 単純なカウントサーバ
type Counter int

func (ctr *Counter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
    *ctr++
    fmt.Fprintf(w, "counter = %d\n", *ctr)
}