Skip to content

Latest commit

 

History

History
445 lines (290 loc) · 18.1 KB

File metadata and controls

445 lines (290 loc) · 18.1 KB

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 iiç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 sakalamak için bellek blokklarını kullanıyor.

Şekil 2.1 Go temel veri yapıları

Programalama ipuçları

Grup halinde değişken tanımalama

Birden fazla tanımala yapcaksanı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 public ya da private kelimesi 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.

// anhatar 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. index kullanarak değer okuyamazsınız, key kullanmanız gerekir.
  • map'in sabit bir boyutu yoktur. slice gibi referans tiplidir.
  • len fonskyionu map içinde çalışır. map'teki key sayısını döner.
  • map'te değer değiştirmek oldukça kolaydır. numbers["one"]=11 formunu 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