Beberapa Cara Menangani Parameter Opsional di Go
Satu hal yang bikin Go beda dari bahasa lain adalah kesederhanaannya. Go nggak punya fitur parameter opsional seperti Python atau JavaScript. Jadi kalau bikin fungsi, kita harus eksplisit soal apa aja parameternya.
Tapi bukan berarti kita nggak bisa bikin fungsi yang fleksibel. Ada beberapa pola yang biasa dipakai developer Go untuk “menyiasati” parameter opsional. Yuk kita lihat satu per satu.
1. Variadic Parameter
Cara paling gampang adalah pakai variadic parameter (...
). Dengan ini, sebuah fungsi bisa nerima argumen dengan jumlah yang nggak pasti.
func greet(message string, names ...string) {
for _, name := range names {
fmt.Printf("%s, %s!\n", message, name)
}
}
func main() {
greet("Hello")
greet("Hello", "Alice", "Bob", "Charlie")
}
message
wajib ada, sedangkan names
bisa kosong, satu, atau banyak.
2. Struct Sebagai Config
Kalau butuh fleksibilitas lebih, bikin aja struct untuk nampung parameter opsional. Dengan gini, kita bisa kasih default value atau validasi.
type GreetOptions struct {
Message string
Names []string
}
func greet(options GreetOptions) {
for _, name := range options.Names {
fmt.Printf("%s, %s!\n", options.Message, name)
}
}
func main() {
greet(GreetOptions{Message: "Hello", Names: []string{"Alice", "Bob"}})
greet(GreetOptions{Message: "Hi", Names: []string{"Charlie"}})
}
Struct ini bisa diisi sesuai kebutuhan. Kalau butuh default, tinggal set saat bikin instance.
3. Functional Options
Ini pola yang cukup populer di komunitas Go, apalagi buat konfigurasi yang kompleks. Caranya: bikin fungsi kecil (option) yang ngubah config utama.
type GreetOptions struct {
Message string
Names []string
}
type Option func(*GreetOptions)
func WithMessage(message string) Option {
return func(o *GreetOptions) {
o.Message = message
}
}
func WithNames(names ...string) Option {
return func(o *GreetOptions) {
o.Names = names
}
}
func greet(options ...Option) {
opts := GreetOptions{
Message: "Hello",
Names: []string{"World"},
}
for _, o := range options {
o(&opts)
}
for _, name := range opts.Names {
fmt.Printf("%s, %s!\n", opts.Message, name)
}
}
func main() {
greet()
greet(WithMessage("Hi"), WithNames("Alice", "Bob"))
}
Awalnya greet
punya default config, lalu tiap option bisa dipakai buat override. Rapi banget kalau parameternya banyak.
4. Chained Config (Fluent Style)
Kalau mau gaya yang lebih “builder pattern”, bisa bikin struct dengan method yang di-chain.
type GreetConfig struct {
Message string
Names []string
}
func NewGreetConfig() *GreetConfig {
return &GreetConfig{
Message: "Hello",
Names: []string{"World"},
}
}
func (gc *GreetConfig) SetMessage(message string) *GreetConfig {
gc.Message = message
return gc
}
func (gc *GreetConfig) SetNames(names ...string) *GreetConfig {
gc.Names = names
return gc
}
func (gc *GreetConfig) Greet() {
for _, name := range gc.Names {
fmt.Printf("%s, %s!\n", gc.Message, name)
}
}
func main() {
NewGreetConfig().
SetMessage("Hi").
SetNames("Alice", "Bob").
Greet()
}
Hasilnya mirip parameter bernama, walaupun Go sendiri nggak punya fitur itu.
Kesimpulan
Go memang nggak punya parameter opsional bawaan, tapi ada banyak cara buat ngakalinnya:
- Variadic: simpel buat argumen yang fleksibel.
- Struct: jelas dan bisa kasih default.
- Functional options: scalable kalau parameternya banyak.
- Builder style: enak dibaca kalau konfigurasi panjang.
Pilih aja sesuai kebutuhan. Nggak ada yang benar/ salah—semua soal trade-off dan konteks.