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
}
}
}