モジュールのレッスン (5/5)
`New...` コンストラクター パターン
Go には constructor キーワードがありません。コンベンションは工場です
適切に初期化された値またはポインタを返す関数。によって
名前は通常、NewT (または NewXxx) と呼ばれます。
ベースパターン:NewT
type User struct {
Name string
Age int
}
func NewUser(name string, age int) *User {
return &User{Name: name, Age: age}
}
u := NewUser("Ada", 36)
fmt.Println(u.Name)直接リテラル &User{...} よりも優れた利点:
- 検証とデフォルトを一元化します。
- エクスポートされていないフィールドがあり、コンストラクターからのみフィールドに値を設定できます。
- 呼び出し元を中断せずに実装を変更できます。
検証付きコンストラクター: (*T, エラー)
初期化が失敗する可能性がある場合は、(*T, error) を返します。
import "errors"
func NewUser(name string, age int) (*User, error) {
if name == "" {
return nil, errors.New("nome obbligatorio")
}
if age < 0 {
return nil, errors.New("eta non valida")
}
return &User{Name: name, Age: age}, nil
}
u, err := NewUser("Ada", 36)
if err != nil {
// handle...
}これは、次のコンストラクターの慣用的なパターンです。 前提条件: データベース接続、ファイルハンドル、サーバー設定など。
複数のコンストラクター
構築する「方法」が複数ある場合は、わかりやすい名前を使用します。
func NewUser(name string) *User { ... }
func NewUserFromJSON(data []byte) (*User, error) { ... }
func NewAdmin() *User { ... }Go ではオーバーロードはありません。名前は曖昧さを解消します。
機能オプション (高度な概要)
オプションのパラメーターが多数ある場合、慣用的なパターンは次のとおりです。 「機能オプション」:
type Option func(*Server)
func WithPort(p int) Option {
return func(s *Server) { s.Port = p }
}
func WithTLS(cert, key string) Option {
return func(s *Server) { s.Cert, s.Key = cert, key }
}
func NewServer(opts ...Option) *Server {
s := &Server{Port: 8080} // default
for _, opt := range opts {
opt(s)
}
return s
}
s := NewServer(WithPort(9000), WithTLS("c.pem", "k.pem"))リテラルよりも冗長ですが、多くのオプションで適切に拡張できます。
パラメータを削除し、下位互換性を維持します (新しい Option を追加します)
既存の呼び出し元を中断しません)。
コンストラクターが必要ない場合
型のゼロ値がすでに有効である場合は、呼び出し元に
直接リテラル。正規の例: sync.Mutex にはコンストラクターがありません。
var m sync.Mutex はすでにすぐに使用できるミューテックスです。 bytes.Buffer についても同様です。
ルールは「ゼロの値を有用なものにする」です。できるなら、いいえ 必須のコンストラクター。
試してみてください
&User{Name: name, Age: age} を返すファクトリー関数 NewUser(name string, age int) *User を記述します。
ヒントを表示
ポインタを返すには、リテラル `&User{...}` を使用します。
3 回の試行後に解決策が利用可能になります
NewUser を (name string) に変換します (*User, error): name == '' の場合、nil、errors.New('nome obbligatorio') が返されます。
ヒントを表示
前提条件がある場合は (*T, error) を返し、失敗した場合は nil + エラーを返します。
3 回の試行後に解決策が利用可能になります
Go におけるコンストラクターの慣用的な慣例は何ですか?
// Which signature is more idiomatic?要約
constructorなし:NewT関数 (または、同じ名前のパッケージ内のNew) を使用します。- 単純な場合は
*Tを返します。(*T, error)前提条件または検証付き。 - エラー時:
nilをポインターとして返し、説明エラーを 2 番目の値として返します。 - 過負荷はありません。わかりやすい名前 (
NewUserFromJSON、NewAdmin) を使用してください。 - 「ゼロ値を便利にする」: 可能であれば、コンストラクターは不要です。
- 多くのオプションパラメータの高度なパターン: 機能オプション。