Pelajaran modul (5/5)
Pola konstruktor `Baru...`
Go tidak memiliki kata kunci constructor. Konvensi ini adalah pabrik
fungsi yang mengembalikan nilai atau penunjuk yang diinisialisasi dengan benar. Oleh
nama itu biasanya disebut NewT (atau NewXxx).
Pola dasar : 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)Keuntungan dibandingkan &User{...} literal langsung:
- Anda mensentralisasi validasi dan default.
- Anda dapat memiliki bidang yang belum diekspor dan mengisinya hanya dari konstruktor.
- Anda dapat mengubah penerapannya tanpa mengganggu penelepon.
Konstruktor dengan validasi: (*T, error)
Jika inisialisasi gagal, kembalikan (*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...
}Ini adalah pola idiomatis untuk setiap konstruktor dengan prasyarat: koneksi db, pegangan file, konfigurasi server, dll.
Banyak konstruktor
Jika Anda memiliki beberapa "cara" untuk membuat, gunakan nama deskriptif:
func NewUser(name string) *User { ... }
func NewUserFromJSON(data []byte) (*User, error) { ... }
func NewAdmin() *User { ... }Tidak ada kelebihan beban di Go: namanya memperjelas.
Opsi fungsional (pandangan sekilas lanjutan)
Ketika ada banyak parameter opsional, pola idiomatiknya adalah "opsi fungsional":
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"))Ini lebih bertele-tele daripada literal tetapi berskala baik dengan banyak pilihan
parameter dan menjaga kompatibilitas ke belakang (menambahkan Option baru
tidak merusak penelepon yang ada).
Ketika Anda TIDAK membutuhkan konstruktor
Jika nilai nol tipe sudah berguna, biarkan pemanggil menggunakan
literal langsung. Contoh kanonik: sync.Mutex tidak memiliki konstruktor,
var m sync.Mutex sudah menjadi mutex yang siap digunakan. Sama untuk bytes.Buffer.
Aturannya adalah: "Jadikan nilai nol bermanfaat". Jika Anda bisa, tidak konstruktor wajib.
Cobalah
Tulis fungsi pabrik NewUser(name string, age int) *User yang mengembalikan &User{Name: name, Age: age}.
Tunjukkan petunjuk
Gunakan `&User{...}` literal untuk mengembalikan pointer.
Solusi tersedia setelah 3 upaya
Ubah Pengguna Baru menjadi (string nama) (*Pengguna, kesalahan): jika nama == '' return nihil, kesalahan.Baru('nome obbligatorio').
Tunjukkan petunjuk
Jika ada prasyarat, kembalikan (*T, kesalahan) dan kembalikan nil + kesalahan jika gagal.
Solusi tersedia setelah 3 upaya
Apa konvensi idiomatik untuk konstruktor di Go?
// Which signature is more idiomatic?Rekap
- Tidak ada
constructor: gunakan fungsiNewT(atauNewdi dalam paket dengan nama yang sama). - Kembalikan
*Tuntuk kasus sederhana;(*T, error)dengan prasyarat atau validasi. - Jika terjadi kesalahan: kembalikan
nilsebagai penunjuk dan kesalahan penjelasan sebagai nilai kedua. - Tidak ada kelebihan beban; gunakan nama deskriptif (
NewUserFromJSON,NewAdmin). - "Jadikan nilai nol berguna": jika bisa, konstruktor tidak diperlukan.
- Pola lanjutan untuk banyak parameter opsional: opsi fungsional.