Open7

Goらしいコード

nqnq

panicを使わずに、errorをちゃんと返し、エラーチェックを確実に行う

nqnq

正規表現を避けてstringsパッケージを使う

nqnq

mapを避ける

メリット

  • フィールドと値を関係がわかりやすくなる
  • フィールドアクセスに対してエディタに補完が効く
  • typoをコンパイル時に検出できる
  • メソッドを追加できる
d := map[string]string {
    "foo": "bar",
    "baz": "qux",
}
type data struct {
    foo string
    baz string
}
d := data {
    foo: "bar",
    baz: "qux",
}

mapの用途

気を付けること

mapに対する操作はスレッドセーフでないこと(複数のgorutineから同時にアクセスしたときに変な値を読み込んだり、プログラムがクラッシュしたりする可能性がある)

そのため、mapに対する操作は排他制御に気を付ける必要がある。
その際にはsync.RWMutexを利用して、簡単なオンメモリのkey-valueを実現する

package main

import(
    "fmt"
    "sync"
)

type KeyValue strcut {
    store map[string]string
    mu sync.RWMutex

func NewKeyValue(kv *KeyValue) Set(key string) (string, bool) {
    kv.mu.RLock()
    defer kv.mu.RUnlock()
    val, ok := kv.store[key]
    return val, ok
}
func main() {
    kv := NewKeyValue()
    kv.Set("key", "value")
    value, ok := kv.Get("key")
    if ok {
        fmt.Println(value)
        }
}

※スレッドセーフとは、マルチスレッド環境において、あるコンピュータプログラムを複数のスレッドで並行して実行しても、問題が生じないように設計された状態や仕様

nqnq

reflectを避ける

Goはreflectパッケージを用いて、リフレクションを行うことができる
が、基本的に使用しないほうが良い

あまり黒魔術的なことをしてコードが分かりづらくなるよりも、素朴に書くのがGoらしい

nqnq

巨大なstructを作らず継承させようとしない

Goはstrcutを定義してメソッドを定義するというオブジェクト指向のようなことができる。

しかし、一般的なオブジェクト指向言語における継承を使ったクラスの階層構造のようなことはできない。

継承がない代わりに、埋め込みを使って委譲させることのみができる

「継承より委譲」

言語機能としてそもそも継承を提供しないというGoの割り切り方

考え方として、たくさんのフィールドを持つような巨大なstrcutを定義するのではなく、再利用可能な小さな部品を組み合わせてデータ構造を定義することを心掛ける

※埋め込むとはある構造体のメンバに別の構造体を持つということ

※ 埋め込みは転送、interfaceをメンバにもつ場合は純粋な委譲

nqnq

並行処理を使いすぎない

レースコンディション(競合状態)のような発見しづらいバグを混入してしまう危険性もある

基本的には直列に書く、ホットスポットで並行処理を活用するのが良い