Lompati ke konten utama
Modul 5 · Pelajaran 5 dari 525/50 dalam kursus~10 min
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

Go
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):

Go
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:

Go
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":

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"))

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

Latihan#go.m5.l5.e1
Upaya: 0Memuat…

Tulis fungsi pabrik NewUser(name string, age int) *User yang mengembalikan &User{Name: name, Age: age}.

Memuat editor…
Tunjukkan petunjuk

Gunakan `&User{...}` literal untuk mengembalikan pointer.

Solusi tersedia setelah 3 upaya

Latihan#go.m5.l5.e2
Upaya: 0Memuat…

Ubah Pengguna Baru menjadi (string nama) (*Pengguna, kesalahan): jika nama == '' return nihil, kesalahan.Baru('nome obbligatorio').

Memuat editor…
Tunjukkan petunjuk

Jika ada prasyarat, kembalikan (*T, kesalahan) dan kembalikan nil + kesalahan jika gagal.

Solusi tersedia setelah 3 upaya

Quiz#go.m5.l5.e3
Siap

Apa konvensi idiomatik untuk konstruktor di Go?

Go
// Which signature is more idiomatic?
Pilihan jawaban

Rekap

  • Tidak ada constructor: gunakan fungsi NewT (atau New di dalam paket dengan nama yang sama).
  • Kembalikan *T untuk kasus sederhana; (*T, error) dengan prasyarat atau validasi.
  • Jika terjadi kesalahan: kembalikan nil sebagai 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.