18 KiB
2.2 Temel Go Bilgisi
Bu bölümde değişken ve sabit değişken tanımlama öğreneceğiz, aynı zamanda Go programala yeteneklerimizi geliştireceğiz.
Değişken tanımlama
Go'da değişken tanımlamanın birden fazla yolu bulunmakta.
var anahtar kelimesi en basit anlamda değişken tanımlamak için kullanılır, Go'da değişken tipinin değişken isminden sonra yazıldığına dikkat edin.
// "variableName" adında "type" tipinde bir değişken tanımlayalım
var variableName type
Birden fazla değişken tanımlama.
// tipi "type" olan 3 değişken tanımlayalım
var vname1, vname2, vname3 type
Öntanımlı değeri olan bir değişken tanımlayalım.
// “variableName” adında, tipi"type" olan ve değeri "value" olan bir değişken tanımlayalım
var variableName type = value
Öntanımlı değeri olan birden fazla değişken tanımlayalım.
//tipi "type" olan ve öntanımlı değerleri sahip üç değişken tanımlayalım.
var vname1, vname2, vname3 type = v1, v2, v3
Yukarıdaki gibi değişken tanımlamak sıkıcı mı geldi? Üzülmeyin, Go ekibide bunu bir problem olarak görüyor. Bu yüzden dolayı değişken tanımlarken değişken tipini ihmal edebiliyoruz. Yani kısaca kod aşağıdaki gibi bir hal alıyor:
//tipi "type" olan ve öntanımlı değerleri sahip üç değişken tanımlayalım.
var vname1, vname2, vname3 = v1, v2, v3
Aslında bu çözümünde yeterince basit olmadığını biliyorum. Bakalım daha neler yapabiliriz.
//tipi "type" olan ve öntanımlı değerleri sahip üç değişken tanımlayalım.
vname1, vname2, vname3 := v1, v2, v3
Şimdi daha iyi gibi.:= kullanarak var ve type ihmal edilebiliyor, buna öz ifade deniyor. Ama bir dakika, tek bir şart var: bu yöntemi sadece fonksiyon içinde kullanabilirsiniz. Fonksiyon gövdesi dışında kullanırsanız derleme hatası alırsnız. Bundan dolayı, global değişkenler için var kullanıyoruz ve kısa tanımalar içinde var() anahtar kelimesini.
_ (boş) özel bir değişken ismi. Verilen her değer yoksayılır. Örneğin, 35değerini b'ye' atıyoruz ve34 değerini yoksayıyoruz.( Bu örnek sadece nasıl çalıştığını gösteriyor. Genelde fonksiyonlardan dönen değerleri yoksaymak için kullanıyoruz )
_, b := 34, 35
Eğer programınızda kullanmadığınız değişkenler varsa, derleme esnasında hata alırsnız. Aşağıdaki kodu derlemeyi deneyin.
package main
func main() {
var i int
}
Sabitler
Sabitler, derleme zamanında belirlenen ve çalışma esnasında da değeri değişmeyen değerlerdir. Go'da integer, string ve boolean değerleri sabit olarak tanımlayabilirsiniz.
Sabitleri şu şekilde tanımlayabilirsiniz.
const constantName = value
// eğer gerekliyse ön tanımlı değerde verebilirsiniz
const Pi float32 = 3.1415926
Örnekler.
const Pi = 3.1415926
const i = 10000
const MaxThread = 10
const prefix = "astaxie_"
Primitif tipler
Boolean
Go'da, boolean tipinde bir değişken tanımlamak için bool anahtar kelimesini kullanıyoruz, değer sadece true ya da false olabilir, ve false öntanımlı değerdir. ( Integer tipi ve boolean tipi arasında tip dönüşümü yapamazsınız! )
// örnek kod
var isActive bool // global değişken
var enabled, disabled = true, false // tipleri yoksayalım
func test() {
var available bool // yerel değişken
valid := false // kısa atama
available = true // değişkene değer atama
}
Sayı tipleri
Integer tipi, işaretli ve işaretsiz olarak iki farklı şekilde kullanılabiliyor. Go'da int ve uint tipleri bulunmakta, ikisininde uzunlukları aynı, tabi bu uzunluk işletim sisteminize göre farklılık gösterebilir. Uzunlukları 32-bit'lik işletim sistemlerinde 32-bit, 64-bit'lik sitemlerde ise 64-bit boyutunda oluyor. Go, aynı zamanda özel boyutları sahip rune, int8, int16, int32, int64, byte, uint8, uint16, uint32, uint64 tiplerinede sahiptir.rune veri tipi int32'e', byte ise uint8'e karşılık geliyor.
Bilmeniz gereken önemli bir konuda bu tipler arası atama yapılamıyor olması, aşağıdaki örnek derleme hatası verecektir.
var a int8
var b int32
c := a + b
Int uint8'den daha uzun olduğu halde, hatta int32 ile aynı boyutta olmasına rağmen, ikisi arasında bir atama yapmak mümkün değil. ( c değişkenin tipinin int olduğu varsayılıyor )
Kayan noktalı sayılar için float32 ve float64 tipleri var, fakat float adında bir tip yoktur... Eğer tip belirtmezseniz öntamımlı olarak float64 tipinde bir değşken oluşturmuş olursunuz.
Peki hepsi bu kadar mı ? Tabi ki hayır! Go kompleks sayılarıda destekliyor. complex128 (64-bit gerçel ve 64-bit sanal kısma sahip) öntanımlı tip, eğer daha küçük boyutta istiyorsanız, complex64 (32-bit gerçel ve 32-bit sanal kısma sahip). RE+IMi formatında yazılabiliyor, RE gerçel ve IM'de sanal kısım olmak üzere, i sanal kısmı belirtiyor. Örnek:
var c complex64 = 5+5i
//output: (5+5i)
fmt.Printf("Value is: %v", c)
String
Go'nun UTF-8'i desteklediğini daha önce bahsetmiştik. String'ler çift tırnak "" ya da backtickler `` gösterilebiliyor.
// örnek kod parçası
var frenchHello string // temel tanımala formu
var emptyString string = "" // boş string tanımlama
func test() {
no, yes, maybe := "no", "yes", "maybe" // kısa atama formu
japaneseHello := "Ohaiou"
frenchHello = "Bonjour" // temel değer atama formu
}
Index kullanarak stringlerin değerlerini değiştirmezsiniz. Aşağıdaki kod derleme esnasında hata verecektir.
var s string = "hello"
s[0] = 'c'
Eğer string'in içindeki bir karakteri değişitirmek istersem bunu nasıl yapacağım? Aşağıdaki kod işinizi görecektir.
s := "hello"
c := []byte(s) // string'i []byte tipine çevir
c[0] = 'c'
s2 := string(c) // tekrar string tipine çevir
fmt.Printf("%s\n", s2)
`+` operator to combine two strings.
+ operatörü ile iki string'i birleştirebilirsiniz.
s := "hello,"
m := " world"
a := s + m
fmt.Printf("%s\n", a)
aynı zamanda.
s := "hello"
s = "c" + s[1:] // indexle karakter değiştiremezsiniz, ama değerleri okuyabilirsiniz.
fmt.Printf("%s\n", s)
Ya string bir satıra sığmayacak kadar büyükse?
m := `hello
world`
`` ` hiç bir karakteri escape etmeyecektir.
Hata tipleri
Go error adında, hata mesajlarını kontrol etmek için, bir veri tipine sahiptir. Bununla beraber hataları idate etmek için errors adında bir pakete sahip.
err := errors.New("emit macho dwarf: elf header corrupted")
if err != nil {
fmt.Print(err)
}
Temel veri yapıları
Aşağıdaki resim Go veri yapısı adlı yazıdan, Russ Cox Blog'undan. Gördüğünüz üzere, Go verileri saklamak için bellek bloklarını kullanıyor.
Şekil 2.1 Go temel veri yapıları
Programlama ipuçları
Grup halinde değişken tanımalama
Birden fazla tanımlama yapacaksanız grup formunu kullanabilirsiniz.
Temel form.
import "fmt"
import "os"
const i = 100
const pi = 3.1415
const prefix = "Go_"
var i int
var pi float32
var prefix string
Grup form.
import(
"fmt"
"os"
)
const(
i = 100
pi = 3.1415
prefix = "Go_"
)
var(
i int
pi float32
prefix string
)
iota belirtimi yapmazsanız, sabit olarak tanımladığınız const() grubundaki ilk değer 0dan başlayacaktır. Eğer sabitlerin değerleri açıkça belirtilmemişse, hepsinin değeri sondaki ile aynı olacaktır. Eğer son değişkenin değeri iota olarak verilmişse, önceki değişkenlerin değerleri iota olarak atanmaycaktır.
iota enumerasyon
Go'daki iota anahtar kelimesi enum oluşturmak için kullanılır, 0 ile başlar, 1 artarak gider.
const(
x = iota // x == 0
y = iota // y == 1
z = iota // z == 2
w // Sabit isminden sonra bir ifade yoksa, en son ifade öntanımlı olarak kullanlacaktır, yani w = iota şeklinde arkaplanda atanacaktır. Buyüzden w == 3 değerine sahip olacaktır.
)
const v = iota // `const` tekrar iota ile karşılaşırsa, tekrar `0` dan başlar, yani v = 0.
const (
e, f, g = iota, iota, iota // e=0,f=0,g=0 hepsi aynı satırda olduğu için.
)
Bazı kurallar
Go'nun kısa ve öz olması, bir takım öntanımlı davranışlara sahip olmasından kaynaklanmakta.
- Değişken ismi büyük harfle başlarsa dışarı açılmış demektir, aksi takdirde private olur.
- Aynı kural fonksiyon ve sabit isimleri içinde geçerli, Go'da
publicya daprivatekelimesi yoktur.
array, slice, map
array(diziler)
array anahtar kelimesi dizi oluşturmak için kullanılır:
var arr [n]tip
[n]tip = > n diznin uzunluğu, tip ise tutacağı elemanların tipi. Diğer dillerde olduğu gibi,[] kullanak değer okuma ya da set etme işlemi yapabiliriz.
var arr [10]int // int tipinde bir dizi
arr[0] = 42 // 0. elemanı 42
arr[1] = 13 // 1. elamanı
fmt.Printf("Dizinin ilk elemanı: %d\n", arr[0]) // 42 dönecektir
fmt.Printf("Son eleman %d\n", arr[9]) // 9. elamanın değerini döncektir,bu örnekte 0(öntanımlı Go veriyor bu değeri).
Boyutta bir dizinin tipini etkilediği için, [3]int ve [4]int farklı tiplerdir, yani dizilerin boyutları değiştirilemez. Eğer dizileri parametre olarak verirseniz, fonksiyonlara kopyalanarak geçerler(referans bazlı değil)! Eğer referans olarak vermek isterseniz, slice veri tipini kullanabilirsiniz. Daha sonra ayrıntılı açıklanacaktır.
Dizi tanımlarken := operatörünü kullanabilirsiniz.
a := [3]int{1, 2, 3} // 3 elemantlı int tipin bir dizi
b := [10]int{1, 2, 3} // 10 elemanlı bir int dizisi, ilk 3 eleman atanmış. Geri kalan elemanların değeri öntanımlı 0.
c := [...]int{4, 5, 6} //`…` kullanarak dizinin uzunluğunu Go'ya hesaplatabilirsiniz.
Dizi tutan diziler tanımalamak isteyebilirsiniz. Bakalım nasıl yapılıyormuş:
// 2 elemantlı 2 boyutlu bir dizi, her elemanı 4 elaman tutuyor.
doubleArray := [2][4]int{[4]int{1, 2, 3, 4}, [4]int{5, 6, 7, 8}}
// Yukarıdaki atama kısa olarak bu şekildede yapılabilir.
easyArray := [2][4]int{{1, 2, 3, 4}, {5, 6, 7, 8}}
Array temel veri yapılarındandır.
Şekil 2.2 Çok boyutlu diziler
slice
Bir çok durumda dizi kullanmak pek uygun olmayabilir, örneğin tutacağımız elemanların sayısı belli olamayabilir. Bu yüzden , "dinamik dizilere" ihtiyacımız var. Go'da bu tip dizilere slice deniyor.
slice tam olarak dinamik dizi değil. Daha çok referans tipli bir veri yapısı. slice aslında boyut gerektirmeyen arraydir. Arkaplanda bir array'e işaret ederler.
// array tanımlar gibi, tek fark boyut bilgisi yok
var fslice []int
slice tanımlayıp, ilklendiriyoruz.
slice := []byte {'a', 'b', 'c', 'd'}
slice daha önce oluşturulmuş array ya da slice kullanılarak tanımlanabilir. slice array[i:j] formunu kullanarak bir diziden tanımlanabilir, i başlangıç ve j bitiş indeksi, ama array[j] formunun bir sliceoluşturmayacağına dikkat edin.
// 10 elemanlı bir dizi tanımlayalım
var ar = [10]byte {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}
// []byte tipinde iki tane slice tanımla
var a, b []byte
// 'a' ar dizisinin 2'den 5'e kadar olan kısmını içeriyor.
a = ar[2:5]
// 'a' ar[3],ar[4] ve ar[5] elemanlarına sahip
// 'b'de ar dizininden oluşan ikinci bir slice
b = ar[3:5]
// 'b' ar[4] ve ar[4] elemanlarını içeriyor
slice ve array tipinin farkına dikkat edin. Go'nun boyutu otomatik ayarlamsı için […], slice tanımalamak için [] kullanıyoruz.
Arakaplandaki veri yapısı şeması.
Şekil 2.3 slice ve array
slice bir kaç pratik özelliğe sahip.
sliceta indeksler 0 dan başlar,ar[:n]=ar[0:n]- İkinci parametrede
slice'ın uzunluğu olacaktır,ar[n:]=ar[n:len(ar)]. ar[:]array'i slice'a çevirir, ilk iki özellikten nedeni çıkarabilir.
slice ile ilgili örnekler
// array tanımla
var array = [10]byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}
// iki tane slice tanımla
var aSlice, bSlice []byte
// bazı pratik işlemler
aSlice = array[:3] // aSlice = array[0:3] aSlice a,b,c elemanlarına sahip
aSlice = array[5:] // aSlice = array[5:10] aSlice f,g,h,i,j elemanlarına sahip
aSlice = array[:] // aSlice = array[0:10] aSlice bütün elemanlara sahip
// slice'tan slice oluşturmak
aSlice = array[3:7] // aSlice d,e,f,g elemanlarına sahip,uzunluk=4,kapasite=7
bSlice = aSlice[1:3] // bSlice aSlice[1], aSlice[2] elemanlarını içeriyor, yani e,f
bSlice = aSlice[:3] // bSlice aSlice[0], aSlice[1], aSlice[2] elemanlarını içeriyor, yani d,e,f
bSlice = aSlice[0:5] // slice kapasite kadar genişleyebilir, bSlice d,e,f,g,h elemanlarını içeriyor
bSlice = aSlice[:] // bSlice aSlice'ın sahip olduğu elemanlara sahip, yani d,e,f,g
slice bir referans tipi, bu yüzden yapılan değişiklikler işaret ettiği dizi ya da slice'ı da etkiler. Örneğin, yukarıdaki aSlice ve bSlice ele alalım, aSlice daki elemanları değiştirirseniz, bSlice'sındaki elemanlarda değişecektir.
slice veri yapısıda struct gibi 3 kısımdan oluşur.
-
slice'ın başlagıcını göstern bir pointer'. -
slice'ın uzunluğu'. -
Kapasite, baslangıç indeksiden
slice'ın uzunluğuna kadar.Array_a := [10]byte{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'} Slice_a := Array_a[2:5]
Yukarıdaki kodun bellekte gösterilmesi aşağıdaki resimde görülebilir.
Şekil 2.4 Slice'ın dizi bilgisi
Slice için dilden gelen yerleşik metodlar mevcut:
len,slice'ın boyutunu verir'.cap,slice'ın kapasitesini verir.'append,slice'a bir ya da daha fazla eleman ekler ve slice`'ı döner .copy, bir slice'ın içerğini diğer bir slice'a kopyalar ve kopyalanan elemanları döner.
Dikkat: append, slice'ın göstediği diziyi değiştirecektir ve aynı diziyi gösteren slice'larıda etkileyecektir. Eğer slice'ın kapasitesi yetmez ise ((cap-len) == 0), append slice için yeni bir dizi oluşturacaktır. Bu durumda eski diziyi gösteren slice'lar etkilenmeyecektir.
map
map, Python'daki sözlük yapısının karşılığıdır.map[keyType]valueTypeformunu kullanarak tanımlanabilir.
Örnek üzerinden gidelim. 'set' ve 'get' işlemleri slice ile aynıdır, ancak slice'ın indeksi sadece int olabilir, map'te ise bir çok tip olabilir: int, string ya da ne isterseniz. Karşılaştırma işlemleri için == ve != operatörleri kullanılabilir.
// anahtar tipi string, değer tipi int olan `map`'i' `make` ile oluştur.
var numbers map[string] int
// oluşturmak için başka bir yol
numbers := make(map[string]int)
numbers["one"] = 1 // atamalar
numbers["ten"] = 10
numbers["three"] = 3
fmt.Println("The third number is: ", numbers["three"]) // değerleri oku
// Çıktı: The third number is: 3
map kullanırken bilmeneniz gerekenler:
map'ler sıralı değildir. Bir map'i her yazdırdığınızda farklı sonuçlar alırsınız.indexkullanarak değer okuyamazsınız,keykullanmanız gerekir.map'in sabit bir boyutu yoktur.slicegibi referans tiplidir.lenfonskyionumapiçinde çalışır. map'tekikeysayısını döner.map'te değer değiştirmek oldukça kolaydır.numbers["one"]=11formunu kullanarak atama yapılabilir.
key:val formunu kullanarak map'in değerlerini ilkleyebilirsiniz, map'in bir key'in var olup olmadığını kontrol etmek için tümleşik fonksiyonlar mevcuttur.
delete kullanarak istediğiniz elemanı silebilirsiniz.
// map'i ilklendir
rating := map[string]float32 {"C":5, "Go":4.5, "Python":4.5, "C++":2 }
// map iki değer döner. İkinci dönen değer aranılan key'in var olup olmadığı bilgisidir. Var ise true yok ise false döner.
csharpRating, ok := rating["C#"]
if ok {
fmt.Println("C# is in the map and its rating is ", csharpRating)
} else {
fmt.Println("We have no rating associated with C# in the map")
}
delete(rating, "C") // "c" elemanını sil
Yukarıda da belirttiğim gibi, mapreferans tipli bir veri yapısıdır. Eğer iki map aynı yeri gösteriyorsa, herhangi bir değişiklik ikisinide etkileycektir.
m := make(map[string]string)
m["Hello"] = "Bonjour"
m1 := m
m1["Hello"] = "Salut" // m["hello"]'nin değeri' Salut oldu
make, new
make; map, slice ve channel gibi tümleşik modeller için bellek ayırma işlemini yapar, new ise tiplerin için çalışır.
new(T) bellekte T tipinde sıfırlanmış yer ayırır ve bellekteki adresini döner, o da *T ki bir pointer. Go'da, öntanımlı olarak T tipinde sıfırla ilklendirilmiş adresi döner.
new pointer döner.
make(T, args) fonksiyonu ise new(T)'den daha farklı işler yapar'. make; slice, map, ve channel için kullanılabilir, bir T tipi döner. Bunun nedeni ise bu 3 yapının bellekte bir alanı gösterbilmesi için ilklendirilmesi gerekir. Örneğin, bir slice bellekte bir array'e işaret eden pointer, boyut ve kapasiteye sahiptir. Bu veriler ilklendirilmeden, slice'ın değeri nildir, bu yüzden slice, map ve channel bellekte oluşturulurken make bu veri yapıları için değerlerini ilklendirip atamalarını yapar.
make boş olmayan değerler döner.
Aşağıdaki resimde new ve make arasındaki fark gösteriliyor.
Şekil 2.5 make ve new bellek ayırma
Sıfır değer, boş değerler demek değildir. Bir değişken tipinin öntanımlı değerleride denebilir. Aşağıda bazı tipler için sıfır değerleri listelnmiştir.
int 0
int8 0
int32 0
int64 0
uint 0x0
rune 0 // rune'un gerçek tipi int32'dir
byte 0x0 // byte'ın gerçek tipi uint8'dir
float32 0 // 4 byte uzunluğunda
float64 0 // 8 byte uzunluğunda
bool false
string ""
Linkler
- İçerik
- Önceki bölüm: "Hello, Go"
- Sonraki bölüm: Kontrol yapıları ve fonksiyonlar




