Go CodeReviewCommentsのまとめ

アプリケーション

概要

github.com - CodeReviewCommentsを読んでメモしておきたいことをまとめる。

Comment Sentences

Copying

  • 別のパッケージから構造体をコピーするときは、予期しない参照に気を付ける。
  • メソッドがポインタの値に関連付けられているならTではなく*Tを使うようにする。

Crypt Rand

  • 鍵の生成にmath/randを使ってはいけない。crypto/randReaderを使う。
    • 文字列として扱いたい場合は16進数かbase64エンコードする。

Declaring Empty Slices

// 長さ0のスライス
t := []string{}

よりも、

// nilのスライス
var t []string

のほうを使うようにする。

JSONオブジェクトのエンコード時、nilnullに変換されるが、[]string{}[]に変換される。

インターフェース設計では両者を区別しないほうがよい。分かりづらいミスを誘発する可能性があるため。

Don't Panic

  • 通常のエラーハンドリングでpanicを使うのは避け、error型を含んだ複数の値を返すようにする。

Goroutine Lifetimes

  • goroutineの生成時は、いつ終了されるかを明確にする。
  • goroutineはchannelの送受信をブロックによってメモリリークを起こす場合がある。
  • ガベージコレクターはブロックされているchannelに到達できなくても、goroutineを停止させない。

Import Blank

  • import _ "pkg"ではパッケージをインポートした際の副作用を利用することができる。
  • この方法はプログラムのメインパッケージもしくはテストのみで利用する。

Import Dot

  • .を使ったimportはimport先のパッケージをimportで指定したパッケージの一部のように扱うため、循環参照を回避することができる。
package foo_test

import (
    "bar/testutil" // fooでもimportされている
    . "foo" // foo_testをfooの一部のように見せる
)

Named Result Parameters

  • 名前付き戻り値は、戻り値が何を意味するかわかりづらいときに使う。

Naked Returns

  • Named Result Parametersと同じ。

Receiver Type

メソッドのレシーバをポインタにするか、値にするかの基準。
迷う場合はポインタにしておく。

ポインタを避けるケース

  • レシーバが、mapfuncchannelならポインタは避ける。
  • レシーバがsliceで、メソッドがsliceを作り直さない場合は、ポインタを避ける。
  • レシーバが小さく、本来値型であったり(ex. time.Time)、変更するフィールドやポインタがない構造体や配列、あるいはintstringのような型の場合は、レシーバが値であるほうが良い場合もある。
    • もし値がメソッドに渡されるとヒープ領域にメモリを確保する代わりにスタックメモリのコピーが行われてしまう。

ポインタにするケース

  • メソッドが値を変更する必要がある場合、レシーバーはポインタにする。
  • レシーバがsync.Mutexか、同期するようなフィールドを持つ構造体ならレシーバはポインタにする。
  • レシーバが大きな構造体や配列の場合は、ポインタにする。
  • 関数が同時実行されたり、メソッドが呼び出されたときにレシーバの値を変更するか?
    • 値渡しではメソッド実行時にレシーバのコピーを生成する。従ってメソッドの外ではレシーバの変更が適用されない。変更がオリジナルのレシーバに適用される必要があるならレシーバはポインタにする。
  • レシーバが値を変更されるかもしれない構造体、配列、スライス、その他の要素である場合、レシーバをポインタにしたほうがコードリーディングしやすい。

Useful Test Failures

テストが失敗したときに伝えるべきメッセージ。

  • 何が悪かったか(≒errorの原因)
  • どんな入力があったか(≒test cases)
  • 実際にどんな値があったか(≒actual)
  • どんな値が来ることを期待していたのか(≒expected)

# 参考