中級のGoエラー 60問
12種類のエラーを、それぞれ複数パターンずつ収録しています。
- strconv.Atoiのerrを無視するとゼロ値のまま処理が進むstrconv.Atoiは変換に失敗するとerrを返しますが、これを無視すると1番目の戻り値は黙って0のままになります。エラーチェックをしないと、変換失敗が気づかれずに処理が進んでしまいます。
- appendの戻り値を再代入し忘れると要素が反映されないappendは新しいスライスを返す関数で、元のスライス変数を直接書き換えません。戻り値を元の変数に代入し直さないと、追加した要素が失われます。
- スライスが元の配列を共有していて予期せぬ書き換えが起きるスライスを別のスライスから切り出すと、多くの場合は同じ配列を参照したままになります。一方を書き換えると、共有している範囲がもう一方にも影響します。
- クロージャがループ外の変数を共有キャプチャして最終値しか残らないforループの外側で宣言した変数をクロージャの中で使い、そのクロージャをスライスに貯めていく場合、各クロージャは同じ変数を参照し続けます。実行時にはループ終了後の最終値だけが全クロージャに共通して見えます。
- all goroutines are asleep - deadlock! の原因と直し方バッファなしチャネルへの送信は、受信するgoroutineが存在するまでブロックします。受信側のgoroutineを起動し忘れると、送信だけが永遠にブロックしデッドロックとして検出されます。
- send on closed channel パニックの原因と直し方close()で閉じた後のチャネルに値を送信しようとすると、実行時にパニックが発生します。チャネルを閉じるのは送信側の役割で、閉じた後は一切送信できません。
- close of closed channel パニックの原因と直し方一度closeしたチャネルをもう一度closeしようとすると、実行時にパニックが発生します。複数箇所からcloseを呼びうるコードでは、どこか1箇所だけが責任を持つ設計にする必要があります。
- 型付きnilをinterfaceに入れると == nil が false になるnilのポインタをerrorなどのinterface型の変数に代入すると、そのinterfaceは型情報を持った「型付きnil」になります。値自体はnilでも、interfaceとしてはnilと等しくなくなります。
- interface conversion panic の原因と直し方型アサーション v.(T) は、vの実際の型がTでない場合に実行時パニックを起こします。2つ目の戻り値(ok)を受け取らずに単一戻り値の形で書くと、失敗時にそのままパニックします。
- sync: negative WaitGroup counter パニックの原因と直し方sync.WaitGroupのDone()はAdd()で加算した回数より多く呼ぶとカウンタが負になり、実行時にパニックします。goroutineの数とAddで加算する数が一致していないと発生します。
- json.Unmarshalで非公開(小文字始まり)フィールドが無視されるencoding/jsonパッケージは、構造体の小文字始まりの非公開フィールドを読み書きできません。JSONのキーに対応するフィールド名を小文字で書いてしまうと、値が入らないままゼロ値になります。
- len(s)がUTF-8のバイト数を返し文字数と一致しないGoの文字列はUTF-8のバイト列として保持されており、len(s)は文字数ではなくバイト数を返します。日本語のようなマルチバイト文字を含む文字列では、見た目の文字数より大きな値になります。