1 Fonksiyon Temelleri

Programlamada, bir fonksiyon belirli bir görevi yerine getiren ve girdi parametreleri ve dönüş değerleri olabilen bir kod parçasıdır. Go dilinde fonksiyonlar, kodu düzenlemek ve tekrar kullanmak için yaygın olarak kullanılır. Fonksiyonları etkili bir şekilde kullanmak, kodu daha öz, okunaklı ve bakımı kolay hale getirebilir.

Fonksiyonlar, Go dilinin temel bir bileşenidir ve fonksiyonların nasıl bildirildiğini ve tanımlandığını anlamak, verimli ve okunabilir kod yazmak için çok önemlidir.

2 Fonksiyon Tanımlama

2.1 Fonksiyon Bildirimi

Go dilinde genel fonksiyon bildiriminin formu şöyledir:

func fonksiyonAdı(parametreler) dönüşTipi {
    // Fonksiyon gövdesi
}

Bu bileşenleri inceleyelim:

  1. func anahtarı bir fonksiyonu bildirmek için kullanılır.
  2. fonksiyonAdı, Go dilinin isimlendirme kurallarını izleyen fonksiyonun adıdır. Büyük harfle başlayan bir fonksiyon dış pakette görünür, küçük harfle başlayan bir fonksiyon ise görünür değildir ve yalnızca aynı paket içinde kullanılabilir.
  3. parametreler, virgülle ayrılmış fonksiyonun aldığı parametrelerin listesidir. Her parametrenin türü belirtilmelidir ve birden fazla parametrenin aynı tipe sahip olması durumunda tür yalnızca bir kez belirtilmelidir.
  4. dönüşTipi, fonksiyonun dönüş değerinin türüdür. Fonksiyon bir değer döndürmüyorsa, bu kısım atlanabilir. Fonksiyon birden fazla değer döndürüyorsa, bunlar parantez içinde olmalıdır.

Örneğin, iki tamsayının toplamını hesaplayan basit bir fonksiyonu şu şekilde bildirebiliriz:

func Topla(a int, b int) int {
    return a + b
}

Bu örnekte, fonksiyon adı Topla, a ve b tipinde iki parametre alır ve dönüş türü int olan bu parametrelerin toplamını döndürür.

2.2 Parametre Listesi

Parametre listesi, fonksiyonun hangi parametreleri kabul ettiğini ve her bir parametrenin türünü tanımlar. Parametreler, bir fonksiyona veri iletmek için kullanılan özel bir değişken türüdür.

func SelamVer(isim string, yaş int) {
    fmt.Printf("Merhaba, %s! Sen %d yaşındasın.\n", isim, yaş)
}

Bu SelamVer fonksiyonunda, isim ve yaş parametreleridir. isim'in türü string, yaş'ın türü ise int'dir. Bu fonksiyonu çağırırken, bu parametreler için gerçek değerler sağlanmalıdır.

2.3 Dönüş Tipleri

Fonksiyonlar hesaplanmış sonuçları döndürebilir ve dönüş türü, fonksiyonun dönüş değerinin veri tipini tanımlar. Bir fonksiyonun dönüş değeri olmayabilir veya bir veya daha fazla dönüş değeri olabilir.

Bir fonksiyonun birden fazla dönüş değeri olduğunda, bunların bildirim sırasında parantez içine alınması gerekir:

func Böl(bölünen, bölen float64) (float64, error) {
    if bölen == 0 {
        return 0, errors.New("sıfıra bölemezsin")
    }
    return bölünen / bölen, nil
}

Buradaki Böl fonksiyonu iki değer döndürür: bölüm ve bir hata mesajı. Eğer bölen sıfırsa bir hata döndürülür.

2.4 Değişken Sayıda Parametreler

Golang'da, bir fonksiyonun tanımlanırken çağrıcının kaç parametre ile çağrılacağını tam olarak bilmediğimiz durumlarda, değişken sayıda parametreler kullanabiliriz. Değişken sayıda parametreler üç nokta ... ile belirtilir ve bu, fonksiyonun herhangi bir sayıda parametreyi kabul edebileceği anlamına gelir. Bu, belirsiz miktarda veri ile ilgilenirken veya belirli türdeki işlevleri uygularken çok kullanışlıdır.

Uygulama Senaryoları

Değişken parametreler aşağıdaki senaryolarda yaygın olarak kullanılır:

  1. String birleştirme: fmt.Sprintf ve strings.Join gibi işlevlerde olduğu gibi.
  2. Dizi/slice işleme: değişken uzunlukta diziler veya slice'larla uğraşırken, toplamı hesaplama veya birden fazla slice'ı birleştirme gibi durumlarda kullanılır.
  3. Günlük kaydı ve hata işleme: Birden fazla hatayla uğraşırken veya birden fazla günlük bilgisini kaydederken, log.Printf veya özel hata özeti işlevleri gibi durumlarda kullanılır.
  4. Yardımcı fonksiyonlar: Kullanıcılara işlevleri çağırma için daha esnek yollar sunmak amacıyla API'lerde veya kütüphanelerde kullanılır.

Değişken Parametreler Kullanımı

İşte değişken parametrelerin basit bir örneği:

// Değişken sayıda tamsayı parametresi alan ve bunların toplamını döndüren bir fonksiyon tanımla
func Topla(sayılar ...int) int {
    toplam := 0
    for _, sayı := range sayılar {
        toplam += sayı
    }
    return toplam
}

func main() {
    // Herhangi bir sayıda parametre geçirebilirsin
    fmt.Println(Topla(1, 2))          // Çıktı: 3
    fmt.Println(Topla(1, 2, 3, 4))    // Çıktı: 10
    
    // Bir dilim geçebilir ve dilimin sonrasına üç nokta işareti koyabilirsin
    sayılar := []int{1, 2, 3, 4, 5}
    fmt.Println(Topla(sayılar...))    // Çıktı: 15
}

Topla fonksiyonunda, sayılar, Topla fonksiyonuna verilen tüm parametreleri içeren bir tamsayı dilimidir. Bu dilim üzerinde döngü kullanarak toplamı hesaplayabiliriz.

Fonksiyon içindeki değişken parametreler aslında bir dilimidir, bu nedenle tüm dilimle ilgili işlemler kullanılabilir. Bir dilimi değişken parametre olarak bir fonksiyona geçirmeniz gerektiğinde, dilimin sonrasına yani ... işaretini ekleyerek yapabilirsiniz.

Değişken parametrelerin kullanılması fonksiyon çağrılarını daha esnek ve özlü hale getirebilir, ancak değişken parametrelerin kullanılması dilim oluşturma ve bellek tahsisi gerektirdiğinden hafif bir performans etkisi olacaktır. Bu nedenle, katı performans gereksinimleri olduğunda dikkatli olunmalıdır.

İpucu: Dilimlerle ilgili detaylı açıklamalar ilerleyen bölümlerde sunulacaktır. Diğer programlama dillerinde deneyiminiz varsa, onları geçici olarak diziler şeklinde düşünebilirsiniz.

3 Fonksiyonları Çağırmak

3.1 Temel Fonksiyon Çağrıları

Bir fonksiyonu çağırmak, fonksiyonun kodunu yürütmek anlamına gelir. Go'da bir tanımlı fonksiyonu çağırmak oldukça basittir, sadece fonksiyon adını kullanın ve uygun parametreleri geçin. Örneğin:

sonuç := ekle(3, 4)
fmt.Println(sonuç)  // Çıktı: 7

Bu örnekte, ekle fonksiyonu çağrılır ve iki tamsayı parametre olarak geçilir, ardından dönen sonuç sonuç değişkenine atanır.

3.2 Parametre Geçme

Bir fonksiyona parametre geçirirken, Go, varsayılan olarak değer ile geçme kullanır, yani parametre değerinin bir kopyasını geçer ve orijinal veri değişmez. Ancak fonksiyonun dış değişkenleri değiştirmesini istiyorsanız veya performans nedenleriyle büyük yapılar geçirmek istiyorsanız, işaretçiler kullanarak veya büyük yapıları geçirerek referans ile geçme yöntemini kullanabilirsiniz.

Değer ile geçme ve referans ile geçme örnekleri şunlardır:

// Değer ile geçme örneği
func ikiyleÇarp(sayı int) {
    sayı *= 2
}

// Referans ile geçme örneği
func ikiyleÇarpPtr(sayı *int) {
    *sayı *= 2
}

func main() {
    değer := 3
    ikiyleÇarp(değer)
    fmt.Println(değer)  // 3, değer değişmeden kalır

    ikiyleÇarpPtr(&değer)
    fmt.Println(değer)  // 6, değer iki katına çıkar
}

Yukarıdaki örnekte, ikiyleÇarp fonksiyonu geçilen sayıyı iki katına çıkarmaya çalışır, ancak yalnızca bir kopyasını iki katına çıkarır, orijinal değer değişkeni değişmez. Ancak ikiyleÇarpPtr fonksiyonu, bir tamsayı değişkeninin işaretçisini parametre olarak alarak orijinal değişkenin değerini değiştirir.