Go Programlama Dili

Go Programa Dili

“Hello World”

Öğrenilen her programlama dilinin ilk örneği “Hello World” ile bizde Go diline  giriş yapalım.

Go dilinde “Hello World” aşağıdaki şekilde yazılır.

package main

 

import “fmt”

 

func main() {

    

    fmt.Println(“hello world”)

}

 

Şimdi bunun ne anlama geldiğini açıklamaya çalışalım.

package: Bu paket bildirimidir. Her Go programı paketler ile başlamalıdır. Paketler Go’nun kodu düzenleme ve yeniden kullanma yöntemidir. “Main” bağımsız bir  çalıştırılabilir dosyalar için gereklidir.

Import “fmt”: Bu ifade ile ekrana çıktısını almak istediğimizi sağlayan Go paketidir. Burada “fm” yi tırnak içine almışız. Bunun gibi çift tırnak kullanımı “dizi değişmezi” olarak bilinir. Burada fmt’yi “import fmt” diyerek çağırdık. Yani dahil ettik.

func:Fonksiyonlar Go programlama dilinin yapı taşıdır. Tüm işlevler “func” ile başlar. Main ismi özeldir çünkü fonksiyonları çalıştırmak istediğimizde buradan çağrılır . “()” bu fonksiyonda kullabacağımız argümanları bu parentezler içerisine dahil ederiz şayet var ise. { süslü parentez ise fonksiyonun başladığı ve bittiği yeri ifade eder.

fmt.Println(“Hello world”): Burada fmt paketinin içinden ekrana yazdırmak için “Println” formatını çağırıyor ve parentez içerisine yazdığımız “Hello World” cümlesini ekrana yazdırıyor.

Temel Veri Tipleri

Go static tip bir progralama dilidir. Kısaca Go çalışmadan önce, değişkenlerinin aldığı veri tipleri bilir ve ona göre hareker eder. Go’nun hızlı olmasının sebeblerinden biri.

Bu yazımızda veri tipleri ile ilgili yüzeysel bir bilgi veriyor olacağım.
<![if !supportLineBreakNewLine]>
<![endif]>

Veri  Tipleri için bir örnek verecek olursam;

”Int16” keyword’nün alacağı max değer 32767, min değer  -32768.
<![if !supportLineBreakNewLine]>
<![endif]>

package main

 

import “fmt”

 

func main() {

 

    var number int16 = 32767

 

    fmt.Println(%T\n, number)

 

}

 

 
Yukarıdaki örneğimizi derlediğimiz zaman sorunsuz çalıştığını göreceksiniz. Ama değişkenimize (number) int16’nın alacağı max değerinden daha fazla bir değer verdiğimizde aşağıdaki şekilde hata alacağız.

 

    var number int16 = 32768

 

.\hello.go:7:6: constant 32768 overflows int16

 

Burada go  bizlere  hafızamda 16BIT’lik bir yer ayırdım diyor ama biz daha fazla bir değer verdiğimiz için hafızada ayrılan yerden daha fazla yer istiyoruz bundan dolayı bizlere hata olarak dönüyor. Değişkenlere verdiğimiz veri tipi değerlerinin max/min değerlerini aşmamamız gerekli.

Birde tanımladığımız veri tiplerini kullanmalıyız. Aksi halde go bizlere  “tanımladığın değişkeni kullanmadığın diye” uyarı veriyor.

Örneğimiz;

 

func main() {

 

    var number int16 = 32767

    var age int = 40

 

    fmt.Println(%T \n, number)

 

}

 

Aldığımız uyarı;

.\hello.go:8:6: age declared but not used

 

String Type: Karakterlerden oluşan veri tipleri. String’in uzunluğu asla negatif olamaz.

Örnek bir tanımlama

 

package main

 

import “fmt”

 

func main() {

 

    var name string = “Go”

 

    fmt.Println(name)

 

}

 

 

Aşağıdaki şekilde çift tırnak içinde boş bir  string tanımlaması yapabiliriz.

var name string = ” “

 

Bool Type: Bool veri tipleri true veya  false döndürür.

var isprime bool = true

 

Yukarıdaki örnekte isprime  bizlere true döndürür.

 

Değişken Tanımlama

 

Bazen bir ismi, bazen bir yaşı, bazen kullanıcıdan aldığımız bir girişi bir yerde saklamak isteriz. İşte programlama dillerinde bu bilgiler bir değişkende   tutulur. Değişkenler static tanımlama yapmadıysak programımız bunları geçiçi bellekte tutar (RAM).

Değişken tanımlama;

var name string=“GO”

 

Burada name isimli string bir değişken tanımladık ve bu değişkenimize “Go” değerini atatık.

Aşağıdaki şekilde bir tanımlamada yapılabilir;

 

    var name string

    

    name=“GO”

 

 

2.tanımlama yöntemi;

var name = “Raskolnikov”

 

3.tanımlama yöntemi;

Bu tanımlamaya short declaration  diyebiliriz.

name := “Raskolnikov”

 

Short declaration’u global değişkenlerde kullanamayız.

4.tanımlama yöntemi;

    var ( 

        name      string = “Raskolnikov”

        age       int    = 30

         

    )

 

5.tanımlama yöntemi;

 

    var firstnamelastnameage = “Raskolnikov”“L.Raskolnikov”30

 

6.tanımlama yöntemi;

 

    firstnamelastnameage := “Raskolnikov”“L.Raskolnikov”30

 

Go’da Scope

 

Sınıf, işlev veya değişken gibi bir program öğesi bildirdiğinizde, adı yalnızca “görünebilir” olabilir ve programınızın belirli bölümlerinde kullanılabilir. Bir adın görünür olduğu bağlam kapsamı olarak adlandırılır.  Örneğin, bir fonksiyon içinde bir değişken bildirirseniz “a” , “a” Bu fonksiyon gövdesinde yalnızca görünür. Yerel kapsama sahiptir. 

func main() {

 

    var car=“fonksiyon Scope”

 

    fmt.Println(“Hello World”)

 

}

 

“Car” değişkeni belirtmiş olduğumuz main fonksiyonu içinde erişilebilir. Kendini kapsayan fonksiyon üzerinden sadece erişilebilir. Buna yerel scope

package main

 

import “fmt”

 

var name = “Package Scope”

 

func main() {

 

    var car=“fonksiyon Scope”

 

    fmt.Println(“Hello World”)

 

}

 

 

Burada name değişkeni global scope alanında. Bundan dolayı name değişkenine  farklı fonksiyonlarda erişebilir.

Örnek;

package main

 

import “fmt”

 

var name = “Package Scope”

 

func main() {

 

    var car = “fonksiyon Scope”

    if true {

 

    }

    fmt.Println(car)

 

    test()

 

}

 

func test() {

 

    fmt.Println(name)

 

}

 

 

 

Aşağıdaki örnekte “blockName” isimli değişkenimizi if bloğu içerisinde tanımladık. Fakat bunu  süslü parantezler dışında kullanmak yani erişmek istedik.

package main

 

import “fmt”

 

var name = “Package Scope”

 

func main() {

 

    var car = “fonksiyon Scope”

    if true {

        var blockName = “Block Scope”

 

    }

 

    fmt.Println(blockName)

 

}

 

 

Bu program çalıştırdığımızda aşağıdaki şekilde hata alırız.

.\hello.go:15:14: undefined: blockName

 

Çünkü bizler “blockName” sadece if içerisinde kullanmak üzere bir tanımlama yaptık. Şayet bunu “car”I tanımladığımız gibi  yerel bir tanımlama yapsaydık bu programızda  çalışıyor olacaktı.

 

Constants

Bir programın çalışması süresi boyunca değişmeyen ve sonradan değiştirilmeyen veri değerledir. Değişkenler oluşturduğunuz şekilde oluşturulurlar, ancak “var” anahtar sözcüğünü kullanmak yerine “const” anahtar sözcüğünü kullanırız:

package main

 

import fmt

 

func main() {

 

    const x string = “Hello, World”

 

    fmt.Println(x)

}

 

 

Aşağıdaki örnekte  const  veri değerimizi değiştirmeye çalışıyoruz
<![if !supportLineBreakNewLine]>
<![endif]>

package main

 

import fmt

 

func main() {

 

    const x string = “Hello, World”

 

    x = “Raskolnikov”

 

    fmt.Println(x)

}

 

Burada derleyicimiz bizlere aşağıdaki şekilde hata veriyor olacak. Const değerimize sonradan atama yapılamaz.

cannot assign to x (declared const)

 

Kontrol Yapıları

For döngüsü;

For döngüsü, bir kod bloğunun birden çok kez tekrarlamamıza izin veren bir ifadedir. Yani 1’den 10’a kadar sayıları ekrana yazdıran bir program yasmak istediğimizde bunu şu ana kadar öğrediklerimiz ile ancak Printf(“1,2,3….”) şeklinde yazabilirdik. Ama  for döngüsü ile bunun daha doğru ve daha sağlıklı bir yolu var.

package main

 

import “fmt”

 

func main() {

 

    i := 1

 

    for i <= 10 {

        fmt.Println(i)

 

        i = i + 1

    }

 

}

 

 

Öncelikle yazdırmak istediğimiz sayıyı kullanmak için “I”adında  bir değişken oluşturuyoruz. Daha sonra for döngüsü ile kaça kadar yazdırmak istiyorsak koşulumuzu veriyoruz. Println(i) ile bunu ekrana yazdırıp, döngümüzün devam etmesi için i değişkenimizin değerini 1 artırıyoruz (tek sayıları yazdırmak isteseydik, i=i+2 yazmamız gerekliydi).

i ye verdiğimiz ilk değer olan 1 for döngüsüne giriyor. Koşulumuzda 1 değerinin 10’dan küçük olup olmadığının kontrolü yapılıyor. 10’dan küçük olduğu için ekrana bir yazdırılıp, bir sonraki ifadeye gelip 1 olan I değişkenimizin değeri,1 artırılarak 2 yapılıyor ve tekrar for döngüsüne giriyor. Döngümüz false olana kadar devam eder.

Go’da while döngü deyimi bulanmamaktadır. Bunun yerine aşağıdaki şekilde bir yapı kullanılır.

package main

 

import fmt

 

func main() {

    i :1

 

    for i < 10 {

        fmt.Println(i)

        i = i + 1

    }

}

 

 

Go da sonsuz döngüyü aşağıdaki şekilde tanımlarız.

 

package main

 

import fmt

 

func main() {

    x :1

 

    for {

        if x == 5 {

 

        }

        fmt.Println(x)

        x += 1

    }

}

 

 

If deyimi

Bir uygulamada koşulun kontrolünü sağlayan deyimdir. Örnek ile açıklamaya çalışalım.

Az önce 1’den 10’a kadar yazdırdığımız sayıları bu sefer tek mi çift mi olduğunu control ederek yazdıralım.

package main

 

import “fmt”

 

func main() {

 

    i := 1

 

    for i <= 10 {

 

        if i%2 == 0 {

            fmt.Println(“Çift”, i)

        } else {

            fmt.Println(“Tek”, i)

 

        }

 

        i = i + 1

    }

 

}

 

 

Burada 1 değerine sahip i değişkenimiz for döngüsü giriyor. 1 değerimiz 10’dan küçük eşit  olduğu için if deyimine  giriyor. İf içerisinde  i’değerimizin çift olup olmadığının kontrolü yapılıyor. 1 değerimiz tek olduğu için İf deyiminin else bloğuna giriyor ve ekrana Tek  1 değerini yazıyor ve if deyiminden çıkıp i değerimizi +1 artırıyoruz.

 

Aşağıdaki şekildede yazabiliriz.

 

package main

 

import “fmt”

 

func main() {

 

    for i := 1; i <= 10; i++ {

        if i%2 == 0 {

            fmt.Println(i, “çift”)

        } else {

            fmt.Println(i, “tek”)

        }

    }

}

 

 

Switch deyimi

package main

 

import “fmt”

 

func main() {

 

    var note int

 

    fmt.Printf(“Lütfen Ders Notunuzu Giriniz”)

 

    fmt.Scan(&note)

 

    switch {

    case note >= 0 && note <= 20:

        fmt.Println(“E aldınız”)

    case note >= 21 && note <= 40:

        fmt.Println(“D Aldınız”)

    case note >= 41 && note <= 60:

        fmt.Println(“C aldınız”)

    case note >= 61 && note <= 80:

        fmt.Println(“B aldınız”)

    case note >= 81 && note <= 100:

        fmt.Println(“A aldınız”)

 

    default:

        fmt.Println(“Hatalı Giriş Yaptınız”)

    }

 

}

 

 

Yukarıdaki örnekte kullanıcıdan bir değer girmesini istiyoruz. Kullanıcı ders notunu yazdıktan sonra, girdiği değer switch case ifadesine giriyor. Kullanıcının girdiği değer case’lerde control ediliyor ve buna göre aldığı ders notuna karşılık o harf getiriliyor. Şayet kullanıcı 0 ile 100 arasında farklı bir sayı girerse  yazmış olduğu değer “default” değerine düşer ve ekranımıza hatalı giriş olarak yazar.

Fonksiyonlar

Fonksiyon belirli bir işlevi yapan kod blokları diyebiliriz. Fonksiyonlar yardımı ile programlarımızı daha işlevsel  hale getirebiliriz. Mesela bir toplama işlemi yaptığımızda bunu kodumuzun farklı yerlerinde tekrar kullanmak istediğimizde, tekrar tekrar tanımlamalar yaparız. Ama bir toplama işlemi yapan fonksiyon yazdığımızda, toplama işlemini yapacağımız yerde toplama fonksiyonunu çağırırız. Ayrıca fonksiyonlar yazdığımız için kodlarımızda çıkacak hataları daha kolay analiz eder, daha rahat  çözeriz.

O zaman ilk  fonksiyon tanımlama ile başlayalım:

func sum(x, y intint {

 

    return x + y

 

}

 

İlk önce fonksiyon olduğunu belirttiğimiz keyword olan func’ı  yazarız. Daha sonra yazacağımız fonksiyonun işlevi ne ise  fonksiyonumuza o ismi yazarız. Fonksiyonumuz parametre alacak ise  benim yazdığımız tanımlamada fonksiyon x ve y int türü iki parametre alıyor. Bu fonksiyonumuzdan int türü bir geri dönüş almak istediğimiz için “int”  yazıyoruz.  Fonksiyonumuz  kendisine verilen iki parametreyi alıp topluyor.

package main

 

import fmt

 

func main() {

 

    fmt.Println(sum(56))

}

 

func sum(x, y intint {

 

    return x + y

 

}

 

 

Her zaman  parametre ve geri dönüş vermek zorundamıyız? Tabi ki hayır;

 

package main

 

import fmt

 

func main() {

 

    sayHi()

}

 

func sayHi() {

 

    fmt.Println(“Hello World”)

}

 

 

Variadik Fonksiyonlar

Ne kadar argüman  alacağını bilemediğimiz bir bir fonksiyonu “variadic” olarak tanımlayabiliriz.

Aslında programlamaya başladığımızdan beri farkında olmadan varayedik fonksiyonlar  kullanıyoruz. Örneğin “Println” fonksiyonu variadik bir fonksiyondur. Aşağıdaki şekilde tanımlarız.

 

func add(args …intint { }

 

“…” 3 nokta bizlerin ne kadar argüman alacağımızı bilmediğimizi ifade ederiz. Parametrelerimiz int türünden ve geri dönüşüde int türünden olduğunu belirtiyoruz.

 

package main

 

import fmt

 

func add(args …intint {

    total :0

    for _v :range args {

        total += v

    }

    return total

}

func main() {

    fmt.Println(add(123))

}

 

 

   “ for _v := range args “ bu ifadeyi for döngü deyimi konusunda işlemedim. Kısaca bu  döngü hakkında da bahsedelim. Bu  aslında  foreach fonksiyonu. Go’da  tanımı yukarıdaki şekilde.

Error

Bir yazılımda beklenilmeyen tüm sonuçlara hata denir.Go’da aşağıdaki şekilde tanımlama yapılır.

package main

 

import (

    “errors”

    fmt

)

 

func main() {

    err :errors.New(“error message”)

 

    fmt.Println(err)

 

}

 

Arrays (Diziler)

Diziler, sabit uzunlukta tek bir türdeki öğelerin numaralandırması diyebiliriz.

Go’da aşağıdaki şekilçe tanımlaması yapılır;

1)

var len[10]int

 

Yukarıda len isimli  10 elemana sahip bir dizi tanımlaması yapıldı. Dizilerde, dizimizin uzunluğunu belirtmeliyiz.

Yukarıdaki örnekte int veri tipli bir dizi tanımladık. Bunun içerisine string bir eleman ekleyemeyiz..

  2-)Aşağıdaki şekilde bir tanımlama yapabiliriz

x := [5]int{1,2, 3, 4, 5}

 

package main

 

import “fmt”

 

func main() {

    var cities [3]string

 

    var (

        city1 string

        city2 string

        city3 string

    )

 

    fmt.Printf(“Lütfen birinci şehri giriniz “)

    fmt.Scanln(&city1)

    cities[0] = city1

    fmt.Printf(“Lütfen ikinci şehri giriniz “)

    fmt.Scanln(&city2)

    cities[1] = city2

    fmt.Printf(“Lütfen üçüncü şehri giriniz “)

    fmt.Scanln(&city3)

    cities[2] = city3

 

    fmt.Println(cities)

}

 

 

Aşağıdaki şekilde çıktı alırız;

[İstanbul Ankara İzmir]

 

Slice

Slice’lar, dizilere benzer şekilde içerisinde birden fazla veri tutabileceğimiz, dizilerin üst kümesi olarak görebileceğimiz tiplerdir. Dizilerden farklı olarak, bu uzunluğunun değişmesine izin verirler. Tanım esnasında bir boyut belirtilmez ve tanım sonrasında istediğiniz kadar eleman ekleyebiliriz.

 

package main

 

import “fmt”

 

func main() {

    var x1 = []int{02468}

 

    x2 := []int{13579}

 

    fmt.Println(“x1:”, x1)

    fmt.Println(“x2:”, x2)

}

 

 

Yukarıdaki  örnekte int  tipinde bir Slice bildiririz. Slice tıpkı bir dizi gibi bildirilir, ancak parantez [] içinde herhangi bir boyut belirtmeyiz. Ayrıca iki farklı tanımlama ile slice’lar oluşturuldu.

Peki  Slices’lar Arraylerden daha fonksiyonel. O zaman neden Arraylere ihtiyaç var go’da?

1-Arraylerin uzunluğunu verdiğimiz ve bu değişmeyeceği için bu daha hızlı ve daha güvenli.

2-Bir Array’in kopyasını aldığımızda, biz Array’in kendisinin kopyasını alıyoruz. Ancak Slice’lerde referansının kopyasını alıyoruz. Array’ler pass by value, Slices ise Pass by Reference

3-Slice’lar Array’lerin üzerine oluşturulmuş bir yapıdır.

 

Append

append, bir dilimin sonuna öğeler ekler. Yeterli kapasite varsa altta yatan dizide, eleman son elemandan sonra yerleştirilir ve uzunluk artırılır. Ancak yeterli kapasite yoksa yeni bir dizi oluşturulur, tüm mevcut elemanlar kopyalanır, yeni eleman sona eklenir ve yeni dilim döndürülür.

 

package main

 

import “fmt”

 

func main() {

    var myArr1 = []int{02468}

 

    fmt.Println(“myArr1”, myArr1)

 

    myArr2 := append(myArr1, 14)

 

    fmt.Println(“myArr2”, myArr2)

 

}

 

 

Çıktısı;

 

myArr1 [0 2 4 6 8]

myArr2 [0 2 4 6 8 1 4]

 

İki Slice’yi  tek bir Slice’ye atamak için aşağıdaki yöntem uygulanır.

 

package main

 

import “fmt”

 

func main() {

 

    fSlc := []int{02468}

    sSlc := []int{13579}

 

    eSlc := append(fSlc, sSlc…)

 

    fmt.Println(“eSlc”, eSlc)

 

}

 

 

Burada “sSlc” Slice’ye dikkat. Burada şayet “…” (spread operatorü) kullanmassak, derleyici bizlere hata verecek.

 

Slice’ye eleman eklemeyi gördük. Peki eleman silme işlemini nasıl yapacağız;

Aşağıdaki örnekte xSlc isimli Slice’mizden ilk 3 elemanı siliyoruz. Bunun için xSlc[3:] yaparak belirtiyoruz.

Burada 3 index numarasından başlayarak “:” koyduğumuz için sonuna kadar gider ve son elemanına kadar yazar.

Şayet biz başından sonuna kadar tüm elemanları silmek ( ya da eklemek ) istersek bunun için;

xSlx[ : ] uygularız.

xSlc[ :3 ]-> uygularsak, burada ilk elemandan başlayarak 3 indeksdeki  elemana kadar gider ama 3 indeksdeki elemanı dahil etmez.

 

package main

 

import “fmt”

 

func main() {

 

    xSlc := []int{0246810}

 

    xSlc = xSlc[3:]

 

    fmt.Println(“eSlc”, xSlc)

 

}

Çıktısı: eSlc [6 8 10]

 

Sondaki iki elemanı silmek için;

package main

 

import “fmt”

 

func main() {

 

    xSlc := []int{0246810}

 

    xSlc = xSlc[:len(xSlc)-2

 

    fmt.Println(“xSlc”, xSlc)

 

}

Çıktısı: xSlc [0 2 4 6]

 

 

Baştan bir eleman sondan iki eleman silmek için;

 

package main

 

import “fmt”

 

func main() {

 

    xSlc := []int{0246810}

 

    xSlc = xSlc[1:]

    xSlc = xSlc[:len(xSlc)-2]

 

    fmt.Println(“xSlc”, xSlc)

 

}

 

Çıktısı: xSlc [2 4 6]

 

 

 

Maps

 

Map’ler Key-Value çiftler şeklinde değerlerini tutmamızı sağlayan veri türleridir.

 

package main

 

import “fmt”

 

func main() {

 

    firstMap := map[int]string{

        10“Cat”,

        11“Dog”,

        12“Penguin”,

        13“Bird”,

        14“Lion”,

    }

 

    fmt.Println(“firstMap”, firstMap)

    fmt.Println(firstMap[12], firstMap[14])

 

}

 

 

Burada  ilk elemanlarımızın hepsi int türünden olmalı ve  ikinci elemanlarımızda string türlerinden olmalı. İnt türünden listede olmayan bir değere ulaşmaya çalışırcak hata almayız ekrana bir şey yazmaz.

Fakat 0 döndürdüğü için biz bunun olup olmadığını nasıl kontrol edeceğiz;

Örnek;

 

package main

 

import “fmt”

 

func main() {

 

    firstMap := map[int]string{

        10“Cat”,

        11“Dog”,

        12“Penguin”,

        13“Bird”,

        14“Lion”,

    }

 

    fmt.Println(“firstMap”, firstMap)

    fmt.Println(firstMap[12], firstMap[14])

 

    valuenumber := firstMap[1]

    fmt.Println(value, number)

 

}

 

 

 

1 değerini number isimli değişkene atayarak ve bunu ekrana yazdırarak öğrenebiliriz.

 

Eleman eklemek için;

 

package main

 

import “fmt”

 

func main() {

 

    firstMap := map[int]string{

        10“Cat”,

        11“Dog”,

        12“Penguin”,

        13“Bird”,

        14“Lion”,

    }

 

    fmt.Println(“firstMap”, firstMap)

    fmt.Println(firstMap[12], firstMap[14])

 

    firstMap[15] = “Bear”

 

    fmt.Println(“firstMap”, firstMap)

 

}

 

 

Eleman silmek için;

package main

 

import “fmt”

 

func main() {

 

    firstMap := map[int]string{

        10“Cat”,

        11“Dog”,

        12“Penguin”,

        13“Bird”,

        14“Lion”,

    }

 

    fmt.Println(“firstMap”, firstMap)

    fmt.Println(firstMap[12], firstMap[14])

 

    firstMap[15] = “Bear”

 

    fmt.Println(“firstMap”, firstMap)

 

    delete(firstMap, 13)

 

    fmt.Println(“firstMap”, firstMap)

    fmt.Println(“Eleman Sayısı”len(firstMap))

 

 

}

 

 

PACKET(PACKAGE)

Go, iyi yazılım mühendisliği uygulamalarını teşvik eden bir dil olarak tasarlanmıştır. Yüksek kaliteli yazılımın önemli bir parçası, “Kendinizi Tekrar Etme” ilkesinde somutlaşan kodun yeniden kullanılmasıdır.

Kodun yeniden kullanımına izin vermek için kullandığımız ilk katman fonksiyonlardır. Go ayrıca kodun yeniden kullanımı için başka bir mekanizma sağlar: paketler. Şimdiye kadar gördüğümüz hemen hemen her program bu satırı içeriyordu:

import “fmt” fmt, biçimlendirme ve ekrana çıktı verme ile ilgili çeşitli foknsiyonları içeren bir paketin adıdır. Paketleme kodu bu şekilde üç amaca hizmet eder:

• Örtüşen adlara sahip olma şansını azaltır ve sırayla foknsiyon  adlarımızı kısa ve özlü tutar.

• Yeniden kullanmak istediğiniz kodu daha kolay bulmanız için kodu düzenler.

• Yalnızca bir programın daha küçük parçalarının yeniden derlenmesini gerektirerek derleyiciyi hızlandırır. fmt paketini kullanmamıza rağmen, programımızı her değiştirdiğimizde onu yeniden derlememiz gerekmiyor.

 

import (

    fmt

    “math”

)

 

func main() {

 

    x :math.Sqrt(64)

    fmt.Println(x)

 

}

 

 

Yukarıdaki örnekte “fmt” paketinin yanında ayrıca math paketini ekledik. Bu paketinin içinde karakök alan fonksiyonu çağırıyoruz.

 

Structs

Go’da class’lar yoktur. Bunun yerine struct’lar ( yapılar) mevcuttur. Struct’lar ile, farklı veri tipleri oluşturulabilir, nesneler oluşturulabiliriz.

Aşağıdaki şekilde tanımlama yapabiliriz

    var employee struct {

        name       string

        lastName   string

        age        int

        department string

    }

 

 Struct’a herhangi bir öğesine ulaşmak için “.” Kullanılır.

fmt.Println(employee.age)

 

 

Herhangi bir öğesine değer vermek için;

package main

 

import “fmt”

 

func main() {

 

    var employee struct {

        name       string

        lastName   string

        age        int

        career string

    }

 

    employee.name = “Amedeo”

    employee.lastName = “Modigliani”

    employee.age = 36

 

    employee.department = “Painter”

 

    fmt.Println(employee.name)

    fmt.Println(employee.lastName)

    fmt.Println(employee.age)   

    fmt.Println(employee.career)

 

}

 

Çıktısı;

 

Amedeo

36       

Modigliani

Painter

 

Bizler her yeni eleman oluşturmak istediğimizde yeni bir struct mı oluşturacağız? Evet buda bir yöntem ama aşağıdaki şekilde bir tip oluşturulup, daha sonra bu veri tipi ile  kendi veri tipimizi oluşturup yeni öğeler ekleyebiliriz.

func main() {

 

    type employee struct {

        name     string

        lastName string

        age      int

        career   string

    }

 

    var e1 employee

 

    e1.name = “Amedeo”

    e1.lastName = “Modigliani”

    e1.age = 36

    e1.career = “Painter”

 

    fmt.Println(e1.name)

    fmt.Println(e1.lastName)

    fmt.Println(e1.age)

    fmt.Println(e1.career)

 

    var e2 employee

 

    e2.name = “Salvador “

    e2.lastName = “Dali”

    e2.age = 85

    e1.career = “Painter”

 

    fmt.Println(e2.name)

    fmt.Println(e2.lastName)

    fmt.Println(e2.age)

    fmt.Println(e2.career)

 

}

 

Yukarıda ”employee” isimli bir tip oluşturuyoruz. Daha sonra employee’den bir  e1  ve e2 isimli employee veri tipi oluşturuyoruz. Böylece istediğimiz  elemanları ekliyor oluruz .e1 ve e2’nin veri tipi struct değil, bunların veri tipi employee

 

Aşağıdaki şekilde de bir tanımlama yapabiliriz

e3:=employee{

         name:“”,

         lastName:“”,

         age:25,

         career:“”,

    }

 

 

GO’da Pointer

 

İşaretçiler, bir değişkenin bellekteki adresini tutan değişkenlerdir. Bir değişkenin bellekteki adresine erişmek için değişkenin önüne “&” işareti eklenir.

package main

 

import fmt

 

func main() {

 

    name :“Raskolnikov”

 

    fmt.Println(&name)

 

}

 

Çıktısı0xc000088230

 

“&” ile değişkenimizin adresini görüntülüyoruz. Benim çıktım sizler yaptığınızda sizin pc’nizde farklı adreste tutabilir.”&” adress operatördür.

 

package main

 

import fmt

 

func main() {

 

    name :“Raskolnikov”

 

    fmt.Println(&name)

 

    fmt.Printf(%T,%v\n, name, name)

    fmt.Printf(%T,%v\n, &name, &name)

 

}

 

Çıktısıstring,Raskolnikov

         *string,0xc000042240

 

İlk “name” şu ana kadar yaptığımız   ve beklediğimiz değerler. Ancak ikinci &name çıktımızın veri tipi *string ve değeri 0xc000042240’dir

 

package main

 

import fmt

 

func main() {

 

     age:=20     

    var number int = &age

 

    fmt.Println(number)

 

}

 

 

Yukarıdaki şekilde  number  veri tipli değişkenimize  “&age” atarsak  hat alırız. Çünkü ikisinin veri tipi farklı. Number “int “ veri tipine sahipken “&age” ise *int veri tipine sahip.

 

Aşağıdaki şekilde bir atama yapabiliriz

package main

 

import fmt

 

func main() {

 

    age :20

    var number *int = &age

 

    fmt.Println(number)

 

}

 

 

Number’a kısa yol ile atama yaparsak;

number := &age

 

“*” operatörü kullandık. Bu ne işe yarar? Bu bizlere depolanan ya da hafızada tutulan adresin değerini  temsil eden bir türü ifade ederB tür bbilgisi nesnenin kendi türünden türetilidr. İnt türden bir nesnenin adresi aşağıdaki şekilde gösterilebilir;

*int   

 

Interface

interface  ile  fonksiyonlardan dönen değerin type’ni  başka bir yerde kullanmak için şekillendirebilir. Arayüzler neslere arasındaki iletişimi sağlamak için kullanılır.

 

type Shape interface {

    area(float64

   }

 

Yukarıda oluşturduğumuz interface özelinde;

 Bir struct gibi,  interface’ler bir type keyword’ü ve isim ve “interface” keyword’ü kullanılarak oluşturulur.

 

package main

 

import fmt

 

type rectangle struct {

    a, b float64

}

 

func (r rectangle) area(float64 {

 

    return (r.a * r.b)

}

 

func (r rectangle) circumference(float64 {

 

    return 2 * (r.a + r.b)

}

 

type shape interface {

    area(float64

    circumference(float64

}

 

func interfaceFunc(i shape) {

 

    fmt.Println(i)

    fmt.Println(i.area())

    fmt.Println(i.circumference())

    fmt.Printf(%Ti)

    fmt.Println()

}

func main() {

 

    r1 := rectangle{84}

    fmt.Println(“Area”, r1.area())

    fmt.Println(“Circumference: “, r1.circumference())

 

    interfaceFunc(r1)

 

}

 

 

 

Neden İnterface’leri kullanırız? Bir örnek vermek gerekirse gittigidiyor, hepsiburada, n11 gibi sitelerden sipariş bilgilerini çekmek istiyoruz. Bu sitelerin birinden bu bilgileri json olarak bir diğerinden xml olarak alıyor diyelim. Biz bir interface kullanarak bunlar arasında ortak bir yapı belirleriz. array dönmek zorunda olan bir getOrderno gibi ortak bir func oluşturur, bu siteler için tanımladığımız nesnelerimiz, oluşturduğumuz interface’yi implement eder. Böylelikle farklı response dönen veriler için ortak bir yapıda veri geleceğinden dolayı, bahsettiğimiz sitelerden gelen verileri işleyecek logicimizi hepsi için farklı farklı kodlar yazmayacak ve test edilebilir bir kod yazmış olacağız.

func main() {

 

    t := triangle{34}

    s := square{4}

    r := rectangle{45}

 

    printArea(t, s, r)

 

}

 

 

 

Goroutines

 

Eş zamanlı olarak yapılan görevlerim tümüne  “Goroutines”denir. Diğer func’lar ile eş zamanlı çalışan diyebiliriz.Bir goroutine oluşturmak için, go anahtar sözcüğünü ve ardından bir func çağrısı kullanırız:

 

package main

 

import fmt

 

func pNumber(int) {

    for i :0i < 10i++ {

        fmt.Println(n, “:”i)

    }

}

func main() {

    go pNumber(1)

    var input int

    fmt.Scanln(&input)

}

 

 


Bu program iki goroutinden oluşmaktadır. İlk goroutin örtüktür ve ana işlevin kendisidir. İkinci goroutin, go f(0)’ı çağırdığımızda oluşturulur. Normalde, bir fonksiyon çağırdığımızda, programımız bir fonksiyondaki tüm deyimleri yürütür ve çağrıyı takiben bir sonraki satıra döner. Bir goroutine ile hemen bir sonraki satıra dönüyoruz ve fonksiyonun tamamlanmasını beklemiyoruz. Bu nedenle Scanln işlevine yapılan çağrı dahil edilmiştir; onsuz, program tüm sayıları yazdırma fırsatı verilmeden önce çıkacaktır.

 

Waitgroup

 

Bazı senaryolarda, bu GoRoutine’lerin ihtiyaçlarınıza göre yürütmelerini tamamlamalarına izin vermek için kodun belirli bölümlerini engellemeniz gerekebilir. WaitGroup’un yaygın bir kullanımı ana işlevi engellemektir, çünkü ana işlevin kendisinin de bir GoRoutine olduğunu biliyoruz.

WaitGroup’u kullanabilmeniz için önce eşitleme paketini içe aktarmanız gerekir. WaitGroup struct türündedir ve kullanabileceğiniz üç işlevi vardır: Add(int), Wait() ve Done(). WaitGroup’un mekaniği, sıfırdan başlayan bir sayaca sahip olmasıdır. Add(int)’i her çağırdığınızda, sayacı Add(int) işlevinde belirtilen parametreyle artırmış olursunuz.

 

Öte yandan, her Done() işlevi sayacı 1 azaltır. Sayaç 0’dan küçükse WaitGroup panikler ve bu nedenle Done()’un gereğinden fazla çağrılmadığını kontrol etmeniz gerekir. Ayrıca, Add()’den önce Done()’u kullanırsanız, paniğe de neden olur. Wait() işlevi kodu engeller ve sayaç sıfır olana kadar serbest bırakılır.

 

Örnekte, önce bir wg değişkeni tanımladık ve yeni bir sync.WaitGroup{} örneğini başlattık. go print()’imizi çalıştırmadan önce Add(1)’i çağırırız. Ardından, yazdırma görevi tamamlandığında Done() işlevini kullanabilmemiz için işaretçiyi print()’de wg öğesine iletiriz. Ana GoRoutine’i engellemek için wg.Wait()’i çağırırız ve go print() bitene kadar bloğu serbest bırakır.

package main

 

import (

    fmt

    “sync”

)

 

func main() {

 

    wg :sync.WaitGroup{}

    wg.Add(1)

 

    go print(&wg)

 

    wg.Wait()

 

    fmt.Println(“hello world”)

}

 

func print(wg *sync.WaitGroup) {

    fmt.Println(“hello Mars”)

    wg.Done()

}

 

 

 

Channels

 

Channels’lar, iki goroutinin birbirleriyle iletişim kurması ve yürütmelerini senkronize etmesi için bir yol sağlar.  Aşağıda bunu kullanarak yapılan örnek bir program;

 

package main

 

import (

    fmt

    “time”

)

 

func pinger(chan string) {

    for i :0; ; i++ {

        c <- “ping”

    }

}

func printer(chan string) {

    for {

        msg := <-c

        fmt.Println(msg)

        time.Sleep(time.Second * 1)

    }

}

 

func main() {

    var c chan string = make(chan string)

    go pinger(c)

    go printer(c)

    var input string

    fmt.Scanln(&input)

}

 

 

Bu program sonsuza kadar ping yazdıracaktır (durdurmak için Enter’a basın). Bir channel türü, channel’da  iletilen şeylerin türü tarafından takip edilen chan anahtar sözcüğüyle temsil edilir (bu durumda, dizeleri geçiyoruz). Sol ok operatörü (<-) kanalda mesaj göndermek ve almak için kullanılır. c <- “ping”, “ping” göndermek anlamına gelir. msg := <- c, bir mesaj almak ve onu msg’de saklamak anlamına gelir.

fmt.Println(<-c) gibi yazılmıştır, bu durumda önceki satırı kaldırabiliriz. Bunun gibi bir kanal kullanmak iki goroutini senkronize eder. Pinger kanalda bir mesaj göndermeye çalıştığında, yazıcı mesajı almaya hazır olana kadar bekler (buna engelleme denir). Programa bir gönderici daha ekleyelim bakalım ne olacak

olur. Bu fonksiyonuda programımıza  ekleyelim.

func ponger(chan string) {

    for i :0; ; i++ {

    c <- “pong”

    }

   }

 

Programızın son hali;

package main

 

import (

    fmt

    “time”

)

 

func pinger(chan string) {

    for i :0; ; i++ {

        c <- “ping”

    }

}

func printer(chan string) {

    for {

        msg := <-c

        fmt.Println(msg)

        time.Sleep(time.Second * 1)

    }

}

func ponger(chan string) {

    for i :0; ; i++ {

        c <- “pong”

    }

}

 

func main() {

    var c chan string = make(chan string)

    go pinger(c)

    go ponger(c)

    go printer(c)

    var input string

    fmt.Scanln(&input)

}

 

 

Programımız şimdi sırayla ping ve pong yazdıracak

Leave a Reply

Site Footer