Menu

Fungsi Variadic di Golang: Parameter ...T dan Spread s...

Fungsi variadic di Go menerima argumen di bagian akhir dengan jumlah berapa pun, dari satu tipe yang sama. Pelajari sintaks ...T, cara mengirim slice dengan s..., jebakan slice yang dipakai bersama, dan cara fmt.Println memakai ...any.

Halaman ini dilengkapi editor yang bisa dijalankan. Edit, jalankan, dan lihat output-nya seketika.

Parameter ...T

Taruh ... sebelum tipe parameter terakhir. Pemanggil lalu bisa mengirim argumen bertipe itu sebanyak apa pun, termasuk tanpa argumen sama sekali. Di dalam fungsi, parameternya berupa slice.

Program ini mencetak 0, 5, dan 10. Tanpa argumen, nums adalah slice nil dengan panjang 0, jadi perulangannya tidak dijalankan.

Parameter biasa boleh ditaruh lebih dulu. Hanya parameter terakhir yang boleh variadic:

func logf(level string, format string, args ...any)

Mengirim slice dengan s...

Kalau kamu sudah punya slice, kamu tidak bisa mengirimnya langsung: sum(nums) gagal dengan cannot use nums (variable of type []int) as int value in argument to sum. Sebarkan dengan ... setelah argumennya:

append juga variadic, dan itulah sebabnya menggabungkan dua slice ditulis append(a, b...).

Spread harus menjadi satu-satunya isi di posisi variadic. sum(1, nums...) gagal dengan too many arguments in call to sum. Bangun slice gabungannya lebih dulu dengan append.

Slice-nya dipakai bersama, bukan disalin

Saat kamu memanggil dengan argumen satuan, Go membuat slice baru untuk argumen-argumen itu. Saat kamu menyebarkan slice yang sudah ada dengan s..., fungsi menerima slice yang sama persis. Menulis ke elemennya mengubah data milik pemanggil.

Output:

[7 8 9]
[0 8 9]

Fungsi variadic yang mengubah parameternya sebaiknya menuliskan hal itu di dokumentasinya, atau menyalin lebih dulu dengan slices.Clone. Sebagian besar fungsi variadic hanya membaca argumennya, jadi masalah ini jarang muncul, tetapi ini perbedaan nyata dari bahasa yang rest parameter-nya selalu berupa array baru.

...any dan cara kerja fmt.Println

fmt.Println dideklarasikan sebagai func Println(a ...any) (n int, err error). any (alias untuk interface{} sejak Go 1.18) menerima semua tipe, jadi kamu bisa mengirim string, angka, dan struct dalam satu panggilan.

Hal pentingnya ada di penerusan: logf meneruskan args... ke Printf. Tanpa titik-titik itu, Printf menerima satu argumen, yaitu []any, dan baris peringatannya tercetak [WARN] [3 8] of %!d(MISSING) workers idle. go vet melaporkan missing ... in args forwarded to printf-like function hanya kalau parameter format diteruskan tanpa diubah, seperti di fmt.Printf(format, args). Di sini format-nya dibangun dengan +, jadi vet diam saja dan titik-titik itu jadi tanggung jawabmu.

[]string tidak bisa disebarkan ke ...any. Tipe elemennya harus sama persis, jadi konversikan lebih dulu:

names := []string{"a", "b"}
args := make([]any, len(names))
for i, n := range names {
	args[i] = n
}
fmt.Println(args...)

Mewajibkan minimal satu argumen

Parameter variadic menerima nol argumen. Kalau fungsinya butuh minimal satu, jadikan argumen pertama sebagai parameter biasa:

Sekarang maxOf() menjadi error kompilasi, bukan pemeriksaan saat program berjalan. Fungsi bawaan max sendiri bekerja dengan cara yang sama: ia butuh minimal satu argumen.

Parameter variadic sebagai argumen opsional

Go tidak punya nilai default untuk parameter. Parameter variadic kadang dipakai untuk meniru satu argumen opsional:

func connect(addr string, timeout ...time.Duration)

Cara ini bisa dipakai tetapi kurang enak dibaca, karena pemanggil bisa mengirim tiga timeout dan signature-nya tidak menjelaskan mana yang dipakai. Untuk lebih dari satu opsi, lebih baik pakai struct konfigurasi, atau pola functional options (...Option, dengan setiap Option berupa fungsi yang mengisi sebuah field). Pola itu memang variadic, tetapi setiap argumennya punya arti yang jelas.

Ringkasan aturan

AturanContoh
Hanya parameter terakhir yang boleh variadicfunc f(a string, b ...int)
Di dalam fungsi, parameternya berupa sliceb bertipe []int
Tanpa argumen menghasilkan slice nilf("x") membuat b == nil
Sebarkan slice dengan ...f("x", nums...)
Spread memakai backing array yang samamenulis ke b[i] mengubah nums
Spread tidak boleh dicampur dengan nilai tambahanf("x", 1, nums...) tidak bisa dikompilasi

Pertanyaan yang sering diajukan

Apa itu fungsi variadic di Go?

Fungsi yang parameter terakhirnya berbentuk ...T, seperti func sum(nums ...int) int. Fungsi ini bisa dipanggil dengan nol argumen atau lebih bertipe T, dan di dalam fungsi parameternya berupa slice []T.

Bagaimana cara mengirim slice ke fungsi variadic di Go?

Tambahkan ... setelah slice-nya: sum(nums...). Slice itu dikirim apa adanya, tanpa disalin, jadi fungsi melihat backing array yang sama. Kamu tidak bisa mencampur spread dengan argumen satuan: sum(1, nums...) tidak bisa dikompilasi.

Apakah Go punya spread operator?

Hanya untuk argumen terakhir di panggilan variadic: f(s...). Tidak ada spread umum untuk membangun array, struct, atau memanggil fungsi non-variadic dengan slice. append(a, b...) adalah aturan yang sama yang diterapkan pada append bawaan.

Apakah fungsi Go bisa punya dua parameter variadic?

Tidak. Hanya parameter terakhir yang boleh variadic, dan hanya ada satu per fungsi. Kirim daftar tambahan sebagai parameter slice biasa.

Ilustrasi bahasa pemrograman di Coddy

Belajar coding dengan Coddy

Mulai