Open2

Go言語100Tipsメモメモ

つっきーつっきー

No.10型埋め込みで起こり得る問題点を意識していない

埋め込み(embedded)

構造体に別の構造体を名前なしで宣言すること。

埋め込むことで、埋め込まれた型のフィールドやメソッドをプロモート(promote)できる。
(=埋め込まれたフィールドやメソッドをその直接利用できる)

type Foo struct {
  Bar //埋め込みフィールド
}

type Bar struct {
  Baz int
}

foo := Foo()
// プロモートされたBazフィールド
foo.Baz = 42

埋め込みの問題点

メモリ内のデータを保持する構造体を作成し、Mutexを使い平行処理から保護をする間違った例。

プロモートにより、sync.Mutex構造体が持つLock()やUnLock()なども外部から実行できてしまう。

type InMem struct {
  sync.Mutex  //埋め込みフィールド
  m map[string]int
}

正しい例。

type InMem struct {
  mu sync.Mutex  //埋め込まない定義
  m map[string]int
}

外部から隠蔽したいデータや振る舞いが構造体にある場合、埋め込みは使わないこと。

つっきーつっきー

No.11関数オプションパターンを使わない

// 設定構造体
type options struct {
    port *int
}

// 設定構造体を更新する関数型
type Option func (options *options) error 

// ポートを更新する設定関数  Option関数型のクロージャを返す
func WithPort(port int) Option {
  return func(options *options) error {
    if port < 0 {
      return errors.New("port should be positive")
    }
    options.port = &port
    return nil
  }
}

// サーバアドレスと一緒に、設定オプションを必要なだけ追加する
func NewServer(adde string, opts ...Option)( //可変個のOption引数を受け取る
  *http.Server, error) {
  var options options // 空の構造体
  for _, opt := range opts {
    err := opt(&options)
    if err != nil {
      return nil, err
    }
  }

  var port  int
  if options.port == nil {
    port = defaultHTTPPort
  } else {
    if *options.port == 0 {
      port = randomPort()
    } else {
      port = *options.port
    }
  }
}