Fonksiyon tanımlamak
Bir fonksiyon tanımı func, bir ad, parametreler, sonuç tipi ve bir gövdeden oluşur. Tip, parametre adından önce değil sonra gelir.
add iki int değer alır ve bir int döndürür. greet hiçbir şey döndürmez, bu yüzden imzasında sonuç tipi yoktur ve gövdesinin return'e ihtiyacı yoktur.
Bir sonuç bildiren fonksiyon sonlandırıcı bir ifadeyle bitmelidir. Bir yol dönmeden kapanış süslü parantezine ulaşabiliyorsa derleyici missing return ile durur.
Tipi ortak olan parametreler
Aynı tipteki ardışık parametreler tek bir tip adını paylaşabilir. func add(a, b int) int, func add(a int, b int) int ile tamamen aynı anlama gelir. Karıştırmak da serbesttir:
func scale(x, y float64, factor int) (float64, float64)
Burada x ve y float64, factor ise bir int'tir.
Dönüş değerleri
Bir fonksiyon sıfır, bir ya da birkaç değer döndürebilir. Birden fazla sonuç parantez içine yazılır ve çağıran onları çoklu atamayla alır:
Bu 3 2 yazdırır. (value, error) çifti bu özelliğin Go'daki en yaygın kullanımıdır ve birden fazla dönüş değeri hakkında kendi sayfası vardır.
Argümanlar kopyalanır
Go her argümanı değerle aktarır. Fonksiyon bir kopya üzerinde çalışır, bu yüzden bir parametreye atama yapmak çağıranın değişkenini asla değiştirmez.
Çıktı şöyledir:
{1 2}
{100 2}
[99 2 3]
Üçüncü satır insanları şaşırtır. Bir slice değeri küçük bir başlıktır (pointer, uzunluk, kapasite). Kopya aynı arka diziye işaret eder, bu yüzden s[0]'a yazmak çağıranın elemanına yazar. Ama fonksiyonun içindeki append yeni bir dizi ayırabilir ve çağıran o yeni başlığı asla görmez. Bir fonksiyon bir slice'ı büyütüyorsa yeni slice'ı döndürün. Aynı mantık map'ler için de geçerlidir: fonksiyon çağıranın göreceği anahtarlar ekleyebilir, çünkü map değeri paylaşılan veriye işaret eder.
Fonksiyonun çağıranın değişkenini değiştirmesi gerektiğinde ya da değer her çağrıda kopyalamak istemediğiniz büyük bir struct olduğunda pointer parametre kullanın.
Fonksiyonlar değerdir
Bir fonksiyonun, adı olmadan yazılan bir tipi vardır: func(int, int) int. Bir fonksiyonu bir değişkende saklayabilir, bir map ya da slice'a koyabilir ve başka bir fonksiyona aktarabilirsiniz.
square, bir değişkene atanmış anonim bir fonksiyondur. Anonim fonksiyonlar çevreleyen kapsamdaki değişkenleri okuyup değiştirebilir de; bu da onları closure yapar.
Adlandırılmış bir fonksiyon tipi, aynı biçim birçok yerde göründüğünde imzaları daha okunaklı yapar:
type Transform func(int) int
func apply(xs []int, f Transform) []int
Bir fonksiyon tipinin sıfır değeri nil'dir. Nil bir fonksiyonu çağırmak invalid memory address or nil pointer dereference ile panic'e yol açar, bu yüzden isteğe bağlı callback'leri çağırmadan önce kontrol edin. Fonksiyon değerleri yalnızca nil ile karşılaştırılabilir, birbirleriyle asla.
Özyineleme
Bir fonksiyon kendini çağırabilir. Go'da tail-call optimizasyonu yoktur, ama goroutine stack'leri ihtiyaç halinde büyür, bu yüzden sıradan özyineleme derinlikleri sorun olmaz.
for i := range 6, 0'dan 5'e sayar ve Go 1.22 ya da sonrasını gerektirir.
Go fonksiyonlarında olmayanlar
- Aşırı yükleme yok. Bir paketteki iki fonksiyon, parametreleri farklı olsa bile aynı adı paylaşamaz.
- Varsayılan ya da adlandırılmış argüman yok. Her parametre her çağrıda sırayla aktarılır. Bir yapılandırma struct'ı size adlandırılmış, isteğe bağlı alanlar verir:
NewServer(Config{Port: 8080}). - İç içe adlandırılmış fonksiyon yok. Bir fonksiyon gövdesinin içinde yalnızca anonim fonksiyonlar tanımlayabilirsiniz; bunlar genellikle bir değişkene atanır.
Değişken uzunlukta argüman listeleri variadic fonksiyonlar ile desteklenir.
Dışa açık ve dışa kapalı fonksiyonlar
Adı büyük harfle başlayan bir fonksiyon (Parse) dışa açıktır ve başka paketlerden çağrılabilir. Küçük harfli bir ad (parse) yalnızca kendi paketinin içinde görünür. public ya da private anahtar kelimeleri yoktur; kuralın tamamı büyük harftir.
Sık yapılan hatalar
- Bir parametre değişikliğinin çağırana ulaşmasını beklemek. Bir parametreye atama yapmak yalnızca kopyayı değiştirir. Yeni değeri döndürün ya da bir pointer alın.
- Bir fonksiyonun içinde append yapıp sonucu yok saymak.
func add(s []int) { s = append(s, 1) }çağıranın slice uzunluğunu etkilemez.func add(s []int) []intyazın ves = add(s)kullanın. - Kullanılmayan sonuçlar. Go bir dönüş değerini yok saymaya izin verir.
go vetatlanan bir hatayı işaretlemez, amaerrcheckgibi linter'lar (golangci-lint'in bir parçası) işaretler._ ='yi yalnızca yok saymak bilinçli bir karar olduğunda kullanın.
Sıkça Sorulan Sorular
Go'da fonksiyon nasıl tanımlanır?
func anahtar kelimesini, bir adı, tiplerin adlardan sonra geldiği bir parametre listesini ve sonuç tipini kullanın: func add(a, b int) int { return a + b }. Sonucu olmayan bir fonksiyon tipi yazmaz, birden fazla sonucu olan bir fonksiyon ise onları parantez içinde listeler: func divmod(a, b int) (int, int).
Go argümanları değerle mi yoksa referansla mı aktarır?
Her zaman değerle. Fonksiyon her argümanın bir kopyasını alır. Bir int ya da bir struct için bu kopya çağıranın değişkeninden bağımsızdır. Slice'lar, map'ler, channel'lar ve pointer'lar paylaşılan veriye işaret eden küçük değerlerdir, bu yüzden işaret ettikleri elemanlardaki değişiklikler çağırana görünür; parametrenin kendisine yeniden atama yapmak ise görünmez. Fonksiyonun çağıranın değişkenini değiştirmesi gerekiyorsa bir pointer (*T) aktarın.
Go'da bir fonksiyon parametre olarak aktarılabilir mi?
Evet. Fonksiyonlar func(int) int gibi bir tipe sahip değerlerdir. O tipte bir parametre tanımlayın ve imzası eşleşen herhangi bir fonksiyonu, adlı ya da anonim, aktarın: func apply(xs []int, f func(int) int).
Go fonksiyon aşırı yüklemeyi ya da varsayılan parametreleri destekler mi?
Hayır. Bir paketteki her fonksiyon adı benzersiz olmalıdır ve her parametre her çağrıda aktarılmalıdır. Yaygın alternatifler farklı adlar (NewServer, NewServerWithTLS), bir yapılandırma struct'ı, variadic parametreler ya da functional options kalıbıdır.