SlideShare une entreprise Scribd logo
1  sur  33
Go Programlama Dili Temelleri
Kitabın önceki bölümünde Go programlama diline genel bir bakış yaparak fikir sahibi olmaya çalışmıştık. Bu
bölümde ise, Go programlama dilinin temel özelliklerine odaklanarak programlama dünyasına giriyoruz.
Bu bölümde, her programlama dili için önemli olan temel programatik nesneler ve dil özelliklerini inceleyeceğiz.
Akış Kontrol
Programlama dillerinin en temel öğelerinden olan akış kontrol mekanizmaları, geliştirilen yazılımın kod
çalıştırma akışını yönetebilmek için kullanılır.
Go dilinde iki temel akış kontrol mekanizması vardır. Bunlar:
- if
- switch
Diğer programlama dillerine göre Go dilindeki if ve switch deyimlerinin daha esnek ve efektif kullanılması
nedeniyle, Go dilinde akış kontrolü yapmak hem kolay hem de daha yönetilebilir bir yapıya sahiptir.
if
En sık kullanacağımız akış kontrolü if deyimidir.
Örnek:
foo := 1
if foo == 1 {
println("bar")
}
Yukarıdaki en basit halini uyguladığımız if kullanımını biraz inceleyelim. foo adında bir kısa değişken
tanımlayarak bu değişkene bir(1) değerini atadık. Sonrasında if akış kontrolüne foo değişkenini vererek “Eğer bu
değişkenin değeri 1 ise, if bloğuna gir” tanımını yapmış olduk! Bu örnek uygulamayı çalıştırdığımızda foo’nun
değeri 1 olduğu için ekranda bar değerini gösterecektir.
Not : foo ve bar değerlerinin bir anlamı yoktur. Bu değerler, yazılım dünyasında dummy data olarak kullanılır.
if gibi akış kontrollerini kullanmanın temel amacı, true ya da false olarak geri dönüş yapan herhangi bir işlemin
sonucuna göre işlem yapabilmektir. Yukarıdaki örnekte tek bir olasılığı programlayarak foo’nun değerine göre
bir altındaki bloğa girişini kontrol ettik. Ancak bu yöntem gerçek uygulamalarda kullanılsa da, genelde yeterli
olmaz. Bizim if akış kontrol üzerinde birden fazla işlemi kontrol ederek uygulamanın akışını değiştirebiliyor
olmamız gerekiyor. Bu akış seçeneklerini çoğaltma işlemini Go dilinde else ve else if ile yapabiliyoruz.
else bloğu : if bloğu şartı sağlanmazsa ve eğer else if bloğu kullanılmadıysa, else bloğu mutlaka çalışır.
Örnek:
age := 15
if age > 13 {
fmt.Println("Yaşınız 13'den büyük olduğu için kayıt olabilirsiniz.")
} else {
cihanozhan.com
fmt.Println("Sosyal platformlar senin için uygun değil!")
}
Örnek çıktısı:
Yukarıdaki örnekte kullanılan yaş değerini 13 olarak değiştirerek tekrar deneyelim.
Örnek çıktısı:
Şimdi de, yukarıdaki örneğe else if bloğunu ekleyerek geliştirelim.
Örnek:
age := 13
if age > 13 {
fmt.Println("Yaşınız 13'den büyük olduğu için kayıt olabilirsiniz.")
} else if age < 13 {
fmt.Println("Sosyal platformlar senin için uygun değil.")
} else {
fmt.Println("Sanırım senin yaşın tam sınırda! Bi düşünelim!")
}
Örnek çıktısı:
Her programlama dilinin akış kontrollerine bakış açısı biraz farklılık gösterebilir. Go dili if akış kontrol
mekanizmasına ek bir yeteneği daha dahil ederek if bloğunun başlık kısmında değişken tanımlamamıza izin
veriyor. Böylelikle, sadece if bloğu içerisinde geçerli olacak değişkenler tanımlayabiliriz.
if foo := 2; foo == 1 {
println("bar")
} else {
println("buz")
}
Yukarıdaki örnekteki if bloğunda tanımlanan foo değişkeni sadece if bloğunda geçerlidir. Bu değişkene
dışarıdan ulaşılamaz.
Örnek çıktısı:
buz
Bu konuyla ilgili akıllara bir soru gelebilir. Eğer biz if bloğundan önce de foo adında bir değişken tanımlarsak,
bu iki aynı isme sahip ama farklı olan değişkenler uygulamanın çalışmasını nasıl etkiler?
Go dili, bu durumu bir hata olarak görmez ve derleme işlemini gerçekleştirir. Çünkü, if bloğundaki değişken ile
dışarıda tanımlanan değişkenlerin çalıştığı etki alanları birbirinden farklıdır.
Örnek:
cihanozhan.com
foo := 5
if foo := 2; foo == 1 {
println("bar")
} else {
println("İç foo: " + " buz")
println("İç foo: " + strconv.Itoa(foo))
}
println("Dış foo: " + strconv.Itoa(foo))
Örnek çıktısı:
if akış kontrol mekanizmasının daha kısa kod yazmak için oluşturulan yöntemini de kullanabiliriz.
Örnek:
func main() {
if v, err := justDoIt(); err == nil {
fmt.Println("value: ", v)
}
}
func justDoIt() (string, error) {
return "", fmt.Errorf("error")
}
Yukarıdaki yöntemde if akış kontrol mekanizmasında değer değişkeni olan v ile birlikte hata yönetimi için
kullanacağımız err nesnesini de tanımlıyoruz. Sonrasında ise hata kontrolü yapacağımız işlemi gerçekleştirecek
olan justDoIt() isimli fonksiyonu err değişkenine atıyoruz. Eğer bu fonksiyon herhangi bir hata mesajı dönerse
if scope başlığında tanımladığımız err nesnesi nil olmayacaktır. Eğer herhangi bir hata ile karşılaşmazsak if
içerisindeki kodlar çalıştırılarak uygulama doğal yaşam döngüsüne devam edecektir.
En son uyguladığımız if örneğini birçok açık kaynak projede sık sık görebilirsiniz. Çünkü bu yöntem kod
kısaltma amacıyla çok sık kullanılır. Ancak bazen de tam aksine kod okunabilirliğini azalttığı için bu yöntem
tercih edilmeyebilir.
switch
Programatik olarak, genellikle switch deyimi if deyimiyle aynı işlemleri yapabilir. switch deyiminin en temel
farkı, if deyiminden daha sade bir yapıya sahip olmasıdır.
Bazı kaynaklarda bu akış kontrol mekanizmasına switch case denildiğini de görebilirsiniz. Bunun nedeni, switch
ile birlikte kullanılması gereken case bloklarıdır.
Örnek:
foo := 2
switch {
case foo == 1:
println("bir")
cihanozhan.com
case foo == 2:
println("iki")
case foo > 3:
println("Üç'ten büyük bir değer")
}
Örnek çıktısı:
İki
Yukarıdaki örnekte foo değişkenine 2 değerini atadık. Sonrasında ise her case bloğu ile bu değişkenin değerini
kontrol ederek girilecek bloğu(yapılacak işlemi) belirledik.
Not : Switch bloğundaki case alanlarıyla, if bloğundaki else if alanları aynı amaçla kullanılır.
Şimdi de, switch ile biraz daha karmaşık bir işlem yaparak, öğrenci notuna göre sınav derecesini ölçelim. Ayrıca
aşağıdaki örnekte switch içerisinde default alanları kullanmayı da inceleyeceğiz.
switch içerisinde default bloğu ne işe yarar?
default bloğunun amacı, if akış kontrolündeki else ile aynıdır. Eğer switch tanımındaki veri ile bloktaki
case’lerden hiç biri eşleşmezse, uygulama default bloğuna girecektir.
Örnek:
var puan float64
fmt.Print("Son sınav puanınızı giriniz: ")
fmt.Scanf("%v", &puan)
switch {
case puan <= 59:
fmt.Println("Dereceniz F")
case puan <= 69:
fmt.Println("Dereceniz D")
case puan <= 79:
fmt.Println("Dereceniz C")
case puan <= 89:
fmt.Println("Dereceniz B")
case puan <= 100:
fmt.Println("Dereceniz A")
default:
fmt.Println("Lütfen 100'den küçük ya da eşit bir değer giriniz.")
}
Not : Go dosyanıza fmt paketini import etmeyi unutmayın!
Örnek çıktısı: Uygulamaya 50 notunu girdik
Dereceniz F
Örnek çıktısı: Uygulamaya 101 notunu girdik
Lütfen 100'den küçük ya da eşit bir değer giriniz.
cihanozhan.com
Konu Ödevi : Şu ana kadar if ve switch akış kontrollerinin kullanımını öğrendiniz. Ancak switch ile yaptığımız
not uygulamasını if ile yapmamıştık! Uygulama ödevi olarak, bu not hesaplama uygulamasını if ile yapınız.
Go dili, if akış kontrolünde olduğu gibi, switch akış kontrolünde de switch deyiminin başlık kısmında değişken
tanımlayarak sadece switch içerisinde geçerli olmak üzere kullanılmasına izin veriyor.
Örnek:
switch foo := 1; foo {
case 1:
println("bir")
case 2:
println("iki")
}
İfadesiz switch kullanımı nedir ve nasıl kullanılır?
İfadesiz switch kullanımı switch’in if akış kontrolü gibi karmaşık işlemlere cevap verebilmesini sağlayan bir
switch genişletmesidir.
number := 75
switch {
case number >= 0 && number <= 50:
fmt.Println("number değeri 0'dan büyük ve 50'den küçüktür")
case number >= 51 && number <= 100:
fmt.Println("number değeri 51'den büyük ve 100'den küçüktür")
case number >= 101:
fmt.Println("number değeri 100'den büyüktür")
}
Peki, switch içerisinde sadece sayısal değerleri mi kontrol edebiliyoruz? Hayır! Metinsel veri de kullanılabilir.
Örnek: switch içerisinde çoklu ifade kullanımı
page := "page2"
switch page {
case "index":
fmt.Println("Ana sayfaya yönlendir.")
case "about":
fmt.Println("Hakkımda sayfasına yönlendir.")
case "page1", "page2", "page3":
fmt.Println("Bu sayfaları yayından kaldırdık!") // Page not found!
default:
fmt.Println("Bu görevi tanımlayamadık!")
}
Örnek çıktısı:
Bu sayfaları yayından kaldırdık!
Yukarıdaki örnekte görüldüğü üzere, bazen ihtiyaç duyacağımız metinsel verilerin switch ile kullanımı da Go
dilinde mümkündür.
cihanozhan.com
Son olarak, switch ile gerçek dünya uygulamalarında kullanabileceğimiz örneklerden birini daha yapalım. Go
dilinin işletim sistemleriyle ilgili açıklamalar yaparken, Go uygulamasının üzerinde çalıştığı işletim sistemi ve
platformu tanıyabildiği ve buna göre işlemler yapabildiğinden bahsetmiştik. Bu işlemi basit bir şekilde
örnekleyelim.
Örnek:
import (
"fmt"
"runtime"
)
func main() {
fmt.Print("Go runs on ")
switch os := runtime.GOOS; os {
case "darwin":
fmt.Println("OS X.")
case "linux":
fmt.Println("Linux.")
default:
// freebsd, openbsd,
// plan9, windows...
fmt.Printf("%s.", os)
}
}
Örnek çıktısı:
Go runs on windows.
Yukarıdaki uygulamanın amacı çok nettir. Go’nun üzerinde çalıştığı işletim sistemini bulmak ve bu işletim
sistemine özgü metodu çalıştırmaktır. Ben Windows işletim sistemi üzerinde çalıştığım için de uygulamanın
çıktısı yukarıdaki gibi oldu.
Bu örnek Go dili tur sayfalarında da kullanılan temel bir örnektir. İlgili sayfayı ziyaret etmek için:
https://tour.golang.org/flowcontrol/9
Fallthrough
…
cihanozhan.com
Diziler
Geliştirilen tüm yazılımların bazı genel gereksinimleri vardır. Bunlardan birisi de, uygulama aktif olarak
çalışırken bilgisayar hafızasında yer tutmaktır. Bunu en temel olarak değişkenler ile gerçekleştiriyoruz. Ancak
bazı durumlarda bu yeterli olmaz. Bazen uygulama içerisinde aynı ya da farklı veri tiplerine sahip birden
fazla(bazen binlerce) veriyi bir bütün olarak tutmak gerekebilir.
Örneğin, switch akış kontrol örneğinde geliştirdiğimiz öğrenci not uygulamasını ele alalım. Bu uygulamadaki
öğrenci notlarının tamamını tek bir nesne içerisinde tutmak isteyebiliriz. Ya da veritabanından elde ettiğimiz
kullanıcılar listesini, uygulama çalışırken hafızada tutmak, uygulama performansı açısından faydalı olacaktır.
İşte bu ve daha birçok nedenden dolayı ihtiyacımız olan bir programlama nesnesi var: Diziler
Diziler için, en basit tabirle değişkenler listesi demek yanlış olmaz. Diziler hakkında detaylı açıklamalara
girmeden önce, kuralları daha iyi benimseyebilmeniz için küçük bir dizi örneği yapacağız.
Dizi İlklendirmek(Array Initialization)
Bir dizi nesnesine değer ataması yapabilmek ya da veri tutmasını sağlayabilmek için öncelikle
ilklendirmek(initialization) yapılmalıdır. Bu işlem, bir dizinin bilgisayar hafızasında eleman sayısı ve veri tipinin
kapasitesi kadar kullanım alanına sahip olmasını sağlar. En basit tabirle, ilklendirilmemiş bir dizi ham bir
nesnedir diyebiliriz. Bu nesneyi kullanıma hazır hale getirmek için de ilklendirme işlemini yaparız.
Örnek:
scores := [3]int{}
Yukarıdaki örnekte, en basit haliyle bir dizi değişkeni tanımladık. Bu dizi değişkeninin adını scores olarak
belirledik ve veri tipi olarak integer, tutacağı eleman sayısının da 3 olacağını bildirdik. Artık bu dizi değişkenini
kullanarak veri ekleyebilir, veriyi elde edebilir ya da değiştirebiliriz.
Şimdi Go dilindeki diğer dizi tanımlama yöntemlerine bir göz atalım.
Otomatik Boyutlandırma İle Dizi Oluşturmak
Bir dizinin eleman sayısı sonradan değiştirilemez. Ancak dizinin oluşturulma aşamasında(ilklendirme) diziye
dinamik değerler vererek bu diziyi dinamik şekilde oluşturabiliriz.
Örnek:
numbers := [...]int{56, 65, 100}
Bu kullanım yönteminin kafaları karıştırmaması için, şöyle bir açıklama getirebiliriz: Bu kullanımda, Go
derleyicisinin davranışı çıkarım yapma üzerine kuruludur. Yani, biz numbers dizisini oluştururken, bu diziye
eklemek istediğimiz veriyi de birlikte gönderiyoruz. Go derleyicisi bu aşamada, bizim gönderdiğimiz
elemanların sayısını toplayarak, geri planda bu eleman adedine göre bir dizi değişkeni oluşturur. Bu da, bizim
ilklendirme aşamasında dinamik eleman sayısına sahip bir değişken oluşturabilmemizi sağlamaktadır.
Short hand Dizi Oluşturmak
Short hand yöntemi söz dizimi olarak ‘Otomatik Boyutlandırma’ yöntemine çok benzese de aynı değildir. Bu
yöntemde amaç, dizi değişken değerinin dinamik olarak belirlenmesi değil, sadece dizinin ilklendirme sırasında
veriyi de birlikte göndermektir.
cihanozhan.com
Örnek:
numbers := [3]int{43, 88, 70}
Yukarıdaki tanımlamada görüldüğü üzere, integer tipine eleman sayısını veren köşeli parantez içerisinde eleman
sayısını belirtiyoruz. Dizi tanımının devamında ise, 3 eleman için değer ataması yapıyoruz.
numbers dizi değişkenini aşağıdaki gibi de tanımlayabilirdik:
Örnek:
numbers := [3]int{43}
Bu tanımlama yönteminde de eleman sayısı değişmez ve gene 3 elemanlı bir dizi değişkeni oluşturduk. Ancak
diğer kullanımdan tek farkı, bu değişkende sadece tek bir değer ataması yaptık. Ve eğer bu kullanımı
uygulayarak dizi değişkenini ekrana yazdırırsak aşağıdaki gibi bir sonuç elde ederiz.
Örnek çıktısı:
[43 0 0]
Görüldüğü üzere, artık 3 elemanlı bir dizi değişkenine sahibiz. Ancak içerisinde sadece tek bir eleman değeri
var. Diğer iki adet sıfır(0) ise, dizinin ilklendirilmesi sırasında Go derleyicisi tarafından atanan başlangıç
değerleridir.
Diziler Hakkında Bilinmesi Gereken Temel Unsurlar
Yukarıda oluşturduğumuz diziyi kullanmak için bilmemiz gereken birkaç ön bilgi daha var.
- Diziler tanımlama sırasında belirtilen eleman sayısı kadar eleman alabilir.
Bilgisayar bilimlerinde dizi kavramının temel kurallarından biri, dizilerin eleman sayısı adedince eleman
alabileceğidir. Ayrıca, bir dizinin eleman sayı sınırı, dizinin ilklendirme işlemi sırasında belirtilmelidir. Bir
diziden bir eleman silinse bile, o elemanın hafızadaki yeri, dizi işaretçisi tarafından bilinir ve kullanılmaya
devam edilir. Silinen elemanın yerine yeni bir değer yazılabilir.
- Dizilerin eleman sayısı sonradan değiştirilemez!
Dizilerin eleman sayısı sonradan değiştirilemez! Programlama dilleri, mevcut bir dizinin eleman sayı sınırını
değiştirebilmek için farklı yöntemler uygulasalar da, bu işlem sadece mevcuttaki değiştirilemezlik sorununu
programcıya yansıtmamak için uygulanan bir çözüm yöntemidir. Mevcut bir dizinin eleman sayı kapasitesini
değiştirdiğinizde, aslında o programlama dili o diziyi geri planda yok eder ve yeni bir dizi oluşturarak önceki
dizinin elemanlarını yeni diziye aktararak kullanmanıza izin verir. Buna genel olarak yeniden
boyutlandırma(resize) işlemi denir ve bu yeterli bir çözümdür.
- Dizilerin elemanlarına index’ler üzerinden erişilir.
Dizilerin elemanlarına elemanların sırası ile değil, elemanların index’leri üzerinden erişilir. Bu kural
programlamaya yeni başlayanların en sık karıştırdıkları konulardan biridir. Dizi elemanlarının sayısı sayma
sayılarıyla(1 … ~) başlar. Ancak, dizi index’leri ise doğal sayılar(0 … ~) ile başlar. Bu nedenle, eğer dizinin ilk
elemanına ulaşmak isterseniz 1 değil, 0 değerini kullanmalısınız.
cihanozhan.com
Dizi Kullanımı
Şimdi daha önce oluşturduğumuz scores adındaki diziyi kullanalım.
Örnek:
scores := [3]int{} // Diziyi ilklendirmiştik!
scores[0] = 34 // Diziye değer ataması yapmak!
scores[1] = 87
scores[2] = 91
fmt.Println(scores) // Diziyi ekrana basalım.
Örnek çıktısı:
[34 87 91]
Bu örnek üzerinden bir dizinin tek bir elemanını elde etmeyi de inceleyebiliriz:
Örnek:
fmt.Println(scores[1]) // Dizinin 1. index’ini almak(2. Eleman)
Örnek çıktısı:
87
Yukarıdaki örnekte, basit bir integer dizi tanımlayarak scores adındaki dizimize integer veri tutacağını
bildirdik. Ayrıyeten, bu dizinin 3 elemana sahip olacağını ve buna göre bir hazırlık yapmasını da Go
derleyicisine iletmiş olduk! Bu bildirim sayesinde, Go derleyicisi bu dizi için hafızada 3 integer kapasiteli hafıza
alanı oluşturacak ve bu hafıza alanlarının adresini scores isimli dizinin işaretçisi(pointer) olarak tanımlayacaktır.
Bu sayede, biz scores üzerinden bu elemanların hafızadaki alanlarına erişebileceğiz.
Başka bir gerçek dünya örneği daha yapalım.
Örneğin, herhangi bir veri kaynağından elde ettiğimiz renk isimlerini bir listede tutmak akıllıca olabilir. Bu renk
listesini uygulama ayakta kaldığı sürece kullanabiliriz. Bu örnekte, elimizde sadece 3 renk(eleman) olacak.
var colors [3]string
colors[0] = "Red"
colors[1] = "Green"
colors[2] = "Blue"
fmt.Println(colors)
Bir Dizinin Eleman Sayısını Bulmak
Go ile yazılım geliştirirken birçok kez eleman sayısını elde etmemiz gerekecek. Bu işlem, Go diliyle birlikte
gelen built-in fonksiyonlarla birlikte çok kolaydır.
Dizi elemanlarının toplamını bulmak için len(arrayName) fonksiyonunu kullanacağız.
Örnek:
// 1. Dizi
var colors [3]string
cihanozhan.com
colors[0] = "Red"
colors[1] = "Green"
colors[2] = "Blue"
// 2. Dizi
var numbers = [5]int{5, 3, 1, 2, 4}
// Dizilerin eleman sayılarının toplamını hesaplayıp ekrana basalım
fmt.Println("Renklerin toplam adedi:", len(colors))
fmt.Println("Rakamların toplam adedi:", len(numbers))
Örnek çıktısı:
Renklerin toplam adedi: 3
Rakamların toplam adedi: 5
Döngü İle Dizinin Değerini Elde Etmek
Şu ana kadar farklı birçok dizi tanımlaması yaptık. Bu tanımlamalar sadece diziler konusunu hızlı kavrayabilmek
için verilen temel seviye örneklerdi. İlerleyen bölümlerde bu nesneleri farklı birçok uygulama içerisinde
kullanacağız. Şimdi bir dizinin içerisindeki veriyi nasıl döngü oluşturarak ekrana yazdıracağımıza bakalım.
Not : Bir sonraki bölümde döngüleri detaylı bir şekilde inceleyeceğiz. Ancak bu bölümde temel seviyede döngü
ile dizi kullanımını örneklememiz dizileri daha iyi kavramanıza yardımcı olacaktır.
Örnek:
strPattern := "Bu değerin x'deki index sırası %d ve değeri %.2fn"
x := [...]float64{65.4, 334.7, 3.21, 97}
for i := 0; i < len(x); i++ {
fmt.Printf(strPattern, i, x[i])
}
Örnek çıktısı:
Döngü ile dizi kullanımı örneğinde, ilk olarak ekranda göstereceğimiz metni programatik format(yer tutucular)
ile birlikte hazırladık. Bu string formatı içerisindeki %d yer tutucu desenini integer gibi sayısal değerleri, %.2f
yer tutucu desenini ise ondalıklı verileri ekrana basmak için kullanıyoruz. Sonrasında x adında, veri tipi float64
olan, içerisinde 4 adet veri olan bir dizi değişkeni oluşturduk. Bundan sonraki satırda ise, döngü işlemine geçtik.
Döngüde dikkat ederseniz i := 0 gibi bir alan mevcut. Bu alanda dizi içerisindeki index’lere eş gelecek değeri
üretecek değişkeni oluşturduk. Ve dikkat ederseniz, bu alanın değeri 0’dan başlamaktadır. Çünkü, hatırlarsanız
dizilerde index değerleri sıfır(0)’dan başlıyordu. Sonrasında ise, len() fonksiyonunu kullanarak x dizisinin
eleman uzunluğunu elde ettik. Ve bu sayede, sıfır(0) index’inden, dizinin eleman sayısına kadar olacak şekilde
bir döngü başladı.
cihanozhan.com
Diziler Referans Tipi Midir? Değer Tipi Mi?
Bu bölümde, bu kitabın ilk bölümünde incelediğimiz referans ve değer tipi kavramının dizilerdeki yansımasını
inceleyeceğiz.
Kısa hatırlatma:
- Referans tipindeki nesneler verinin hafızadaki adresini tutarlar ve kopyalanırken de hafıza adresini
kopyalarlar. Verinin kendisini değil!
- Değer tipindeki nesneler verinin kendisini tutar ve kopyalanması halinde verinin kendisini kopyalar
Peki diziler referans tipine mi dahiller, yoksa değer tipine mi?
Örnek:
co := [...]string{"Turkey", "USA", "China", "India", "Germany"}
x := co // co nesnesini x adında yeni oluşturulan bir diziye atadık!
x[0] = "Pakistan"
fmt.Println("co değeri: ", co)
fmt.Println("x değeri: ", x)
Örnek çıktısı:
Yukarıdaki örnek çıktıyı yorumlayalım:
co adında yeni bir dizi değişkeni oluşturarak, bu değişkene 5 adet ülke adını veri olarak ekledik. Sonraki satırda
x adında yeni bir değişken oluşturduk. Bu oluşturduğumuz x değişkenine de co adındaki dizi değişkeni atadık!
Bunun anlamı, ‘co dizisindeki değerleri x’e kopyala’ demektir. Buraya kadar her şey olağan! Sonraki satırda
ise x değişkeninin sıfırıncı(0) index’indeki Turkey değerini değiştirmek istedik. Eğer diziler bir referans tipi ise
bu değer ataması x dizisinin işaretçisi üzerinden co değişkeninin de verisini değiştirecektir. Ancak sonuç
çıktısından görüldüğü üzere, x dizisi üzerinde yapılan bir değişiklik sadece x’i etkilemektedir. Bu değişiklik co
dizisini etkilememektedir. Bu sonuç da bize dizilerin bir değer tipi olduğunu ispatlamaktadır.
Çok Boyutlu Diziler
Çok boyutlu diziler, her bir item’ında bir dizi bulunduran dizilerdir. Normal dizilerin her item’ında sadece tek bir
eleman, yani değer vardır. Ancak çok boyutlu diziler, her item’ında birer dizi taşırlar. Bu nedenle, çok boyutlu
bir diziden elde edilen her item’ın da alt elemanları elde edilebilir.
Not : Bu konu çok karmaşık gibi görünebilir. Ancak çok boyutlu bir dizinin temel prensipleri çok açıktır. Bu
prensipleri anladığınız takdirde tüm çok boyutlu dizi yapılarını rahatlıkla anlayabilir ve oluşturabilirsiniz.
Basit bir çok boyutlu dizi oluşturalım. Bu dizi 3’e 2’lik bir yapıya sahip olsun.
Örnek:
var unicorn [3][2]string
Yukarıdaki çok boyutlu diziyi string veri tipinde oluşturduk. Diziyi oluştururken belirttiğimiz 3 ve 2’lik sayılar
ise dizinin temel yapısını tanımlıyor. Buradaki 3 sayısı ana dizinin kaç eleman alacağını belirtir. Bu 3 dizi
cihanozhan.com
elemanının her bir item’ı ise birer dizi alacaktır. Ve aynı zamanda bu 3 dizi item’ın her birinin kapasitesi de 2
string eleman alacak şekilde oluşturulmuştur.
Şimdi bu oluşturduğumuz unicorn isimli çok boyutlu değişkene veri ekleyelim.
unicorn[0][0] = "Apple"
unicorn[0][1] = "Google"
unicorn[1][0] = "Microsoft"
unicorn[1][1] = "Uber"
unicorn[2][0] = "Facebook"
unicorn[2][1] = "Oracle"
Veri ekleme kodlarına dikkat ederseniz, soldaki index’ler 0’dan başlayarak 2 dahil 2’ye kadar gidiyor. Bunun
anlamı, 3 elemanlı bir dış diziye sahibiz. Sağdaki index alanlarında ise, sadece 0 ve 1’ler mevcut! Bunun anlamı
ise, sadece 2 adet eleman alabilen bir iç diziye de sahibiz. Bu örnekteki her dış dizi, 2 eleman alabilen bir iç
diziye sahiptir.
Bu çok boyutlu dizi içerisinden istediğimiz bir veriye nasıl ulaşabiliriz?
Eğer sadece tek bir veriyi bulmayı hedefliyorsak ve yukarıdaki gibi bir dizilime sahipsek, aşağıdaki gibi
yapabiliriz.
Örneğin, Uber verisini elde etmek istiyorsak:
Örnek:
fmt.Println(unicorn[1][1])
Örnek çıktısı:
Uber
Aynı şekilde bu yöntem ile veri değişikliği de yapabiliriz.
Örnek:
unicorn[1][1] = "Yahoo"
fmt.Println(unicorn[1][1])
Örnek çıktısı:
Yahoo
Çok boyutlu dizilerin bir başka oluşturulma yöntemi ise aşağıdaki gibidir:
Örnek:
// Diğer bir çok boyutlu dizi oluşturma yöntemi
data := [3][2]string{
{"apple", "pear"},
{"banana", "cucumber"},
{"lemon", "watermelon"},
}
Not : Döngüler konusu ve range kullanımı bir sonraki bölüm olan Döngüler bölümünde detaylı bir şekilde
cihanozhan.com
anlatılmaktadır. Ancak döngülerin diziler ve dizilerden veri elde etmede aktif olarak kullanılması nedeniyle bu
bölümde de bir örnekle incelenmiştir. Bir sonraki bölümde döngü yapılarını inceledikten sonra tekrar bu örneğe
göz atmanızı öneririm.
// Çok boyutlu dizinin her bir item'ını iç içe döngü ile ekrana basmak
// loop1 döngüsü, yukarıda tanımlanan data üzerinde dış dizi için döner
// loop1 her item’ında loop2’nin bir iç diziye sahip olmasını sağlar
for _, loop1 := range data {
// loop2 döngüsü, loop1 üzerinde bir iç dizi almak için döner
for _, loop2 := range loop1 {
fmt.Printf("%s ", loop2)
}
fmt.Printf("n")
}
Örnek çıktısı:
apple pear
banana cucumber
lemon watermelon
Döngüler
Programlama dünyasında, tekrar eden bazı işlemleri yapmak gerekebilir. Bu bazen bir veritabanından elde edilen
veri üzerinde, bazen de network üzerinden elde edilen veri paketleri üzerinde işlem yapmak olabilir. Bu tür
işlemleri yapabilmek için, belirli kurallara göre işlemleri tekrar edebilme yeteneği gerekir. Programlama
dünyasında bu amaçla çalışan nesnelere döngüler diyoruz. Bu bölümde, Go dilinin döngü yeteneklerini
inceleyeceğiz.
Go programlama dilinde diğer diğer dillerin aksine tek bir döngü yapısı vardır: for
for
Diziler konusunu incelerken for döngüsünü dizi örnekleri üzerinde kullanmıştık. Şimdi bu bölümde for
döngüsünü detaylı şekilde inceleyeceğiz.
for söz dizimi:
for başlatma; şart; işlem {
}
İlk basit for örneğimizi oluşturalım ve inceleyelim.
Elimizde basit bir ekrana yazma işlemi var ve bunu N defa yapacağız.
Örnek:
for i := 0; i < 5; i++ {
fmt.Println("i'nin değeri:", i)
}
Örnek çıktısı:
cihanozhan.com
i'nin değeri: 0
i'nin değeri: 1
i'nin değeri: 2
i'nin değeri: 3
i'nin değeri: 4
Not : Bu for döngü yöntemi C-family dillerin tümünde geçerli bir kullanımdır. Go dili de C dilinin bir çok iyi
yönünü bünyesine dahil ettiği için, bu kullanımı olduğu gibi desteklemektedir.
Yukarıdaki örnekte, ekrana yazma işlemini 5 kez tekrarlamayı sağlayan bir kod yazdık. Şimdi bu kullanımı adım
adım inceleyelim.
- başlatma: Bu alanda bir değişken tanımlayarak for döngü bloğunun bu değişkenin değeri ile
kontrol edilebilmesi sağlanır. Bu değişken genel olarak sıfır(0)’dan başlatılır ve döngü her
çalıştığında, istenen algoritmaya göre değişmekle birlikte, azaltılır ya da artırılır. Bu sayede
döngünün belirtilen işlemi kaç kez yaptığını bilebiliriz. Bu değişken sadece for döngü bloğunun
içerisinde geçerlidir. Bu değişkene dışarıdan erişilemez.
- şart: başlatma bloğunda tanımlanan değişkenin değeri için bir şart belirtmemizi sağlar. Örneğin, i <
5 olduğu sürece devam et gibi bir şart verebiliriz.
- işlem: bu scope ise döngünün yönünü belirler. Başlatma bloğunda tanımlanan değişkenin ileri ya
da geri olacak şekilde, artırılması ya da azaltılmasını sağlayarak uygulama sürecinde belirleyici rol
oynar.
Eğer for döngüsünün şart alanını boş bırakırsak ne olur?
Eğer for döngüsünün şart alanını boş bırakırsak, döngünün bir bitiş değeri(limiti) olmayacaktır. Bu da doğal
olarak bir sonsuz döngü tanımladığımız anlamına gelir.
Not : Aşağıdaki kodu çalıştırdıktan sonra sonsuz döngü oluşacaktır. Visual Studio Code editöründe sonsuz
döngüyü kırmak için terminal üzerindeyken CTRL+C klavye kombinasyonunu kullanmanız yeterlidir.
Örnek:
for i := 0; ; i++ {
fmt.Println("i'nin değeri: ", i)
}
Örnek çıktısı
…
i'nin değeri: 2837
i'nin değeri: 2838
i'nin değeri: 2839
…
Eğer döngünün işlem alanını boş bırakırsak ne olur?
Eğer döngünün işlem alanını boş bırakırsak, döngü gene sonsuz döngü olacaktır. Ancak döngünün yönünü
belirtmediğimiz için i değişkeninin değeri artmayacak ve ekrana sürekli sıfır(0) değeri yazılacaktır. Bu kullanım
çok özel durumlar haricinde kullanılan bir yöntem değildir. Ancak for döngüsünün davranışlarını anlayabilmeniz
için önemlidir.
Örnek:
for i := 0; i < 3; {
cihanozhan.com
fmt.Println("i'nin değeri: ", i)
}
Örnek çıktısı:
…
i'nin değeri: 0
i'nin değeri: 0
i'nin değeri: 0
…
for ile While Döngü Yöntemi Oluşturmak
Normal bir for kullanımında oluşturduğumuz başlatma değişkeni sadece for scope’u içerisinde geçerli olduğu
için bu değişkene dışarıdan erişemeyiz. Ancak bazen döngü içerisinde üretilen ve değeri değişen veriye döngü
dışından erişme ihtiyacımız olabilir. Şimdi bu durumu nasıl yönetebileceğimize bakalım.
Örnek:
x := 1
for x <= 10 {
fmt.Println("x değeri: ", x)
x += 1
}
Yukarıdaki örnekte, for scope’u dışında x adında bir değişken tanımladık ve bu değişkenin for scope’u
içerisinde kullanılmasını sağladık. Bu sayede, döngünün içerisinde üretilen yeni değerlere döngünün dışından da
erişebildik. Ayrıca, dikkat ederseniz normalde işlem scope’unda yaptığımız değer artırma işlemini de for
döngüsünün içerisinde yaptık.
Örnek sonucu:
range
Önceki bölümlerde diziler üzerine birçok işlem gerçekleştirdik. Dizileri hatırlarsanız, döngü ile dizilerin her bir
item’ını elde ederek, bu item’lar üzerinde çeşitli işlemler yapabiliyorduk. Ancak modern yazılım geliştirme
süreçlerinde, bir integer’dan daha karmaşık veri tiplerine sahip dizi nesneleri üzerinde çalışmamız
gerekmektedir. Bu tür karmaşık diziler üzerinde iteration(tekrarlama) uygulayabilmek için Go diline eklenen
for döngü yapısına da range diyoruz.
Not : C# programlama diliyle ilgilenenler için; Go dilindeki for range uygulaması(implementation), C#
dilindeki foreach döngü yapısının Go dilindeki karşılığıdır.
cihanozhan.com
Söz dizimi:
for key, value := range arrayObject {
println(key, value)
}
Şimdi for range ile ilgili basit bir örnek yapalım.
Örnek:
nums := []int{5, 6, 7}
sum := 0
for _, num := range nums {
sum += num
}
fmt.Println("toplam: ", sum)
Örnek çıktısı:
toplam: 18
Yukarıdaki for range döngüsünde nums dizisi üzerinde bir tekrarlama işlemi yaptık. Yalnız dikkat ederseniz,
for tanımından sonraki “_, num” kısmında bir alt çizgi kullandık. Bunun nedeni, for range yapısının bize iki
değer veriyor olmasıdır. Bu değerlerden ilki elemanın index’i, diğeri ise elemanın değeridir. Ancak biz bu
uygulamada elemanın index’ini almak istemediğimiz için, index alanına bir değişken adı vermek yerine, alt
çizgi( _ ) kullandık. Eğer bu index değerine de ihtiyacımız var ise, şu şekilde bu değeri elde edebiliriz.
Not : Kitabın ilk bölümlerinden hatırlarsanız, Go dili tanımlanmış ama kullanılmamış nesnelerin kod içerisinde
bulunmasına izin vermiyor ve derleme zamanında hata fırlatıyor. Bu nedenle, döngünün index alanında bir
değişken tanımlarsanız, onu kullanmak zorunda kalırsınız. Aksi halde, alt çizgi ile bu sorunu çözebiliyoruz.
Örnek:
nums := []int{5, 6, 7}
sum := 0
for ind, num := range nums {
sum += num
fmt.Println("index: ", ind)
}
fmt.Println("toplam: ", sum)
Örnek çıktısı:
index: 0
index: 1
index: 2
toplam: 18
Go dilinde for range döngü modelini birçok farklı nesne(map, slice, struct vb.) üzerinde kullanabiliyoruz. Bu
nesnelerin bir kısmını henüz incelemediğimiz için, bu örneklerle ilgili uygulamaları sonraki bölümlere
bırakıyoruz.
cihanozhan.com
Bir for döngüsündeki range yapısını farklı bir şekilde de kullanabiliriz. Örneğin, elimizde bir liste var ama
verinin kendisini elde etmeden sadece veri adedince bir işlemin gerçekleştirilmesini istiyorsak aşağıdaki
yöntemle veriyi göz ardı ederek veri adedince dönen bir döngü oluşturabiliriz.
list := map[string]string{
"X": "Ferrari",
"Y": "Jaguar",
}
for range list {
fmt.Println("Dönüyor")
}
Örnek çıktısı:
Dönüyor
Dönüyor
Son uyguladığımız döngü yapısı biraz anlamsız gibi görünebilir. Ancak bu yöntemi Go dilindeki channel
nesneleriyle birlikte kullanılabiliyoruz.
break ve continue
Döngüler gerekli şartlar sağlanana kadar dönmek üzere tasarlanan nesnelerdir. Ancak bazen bir döngünün iç
akışını kontrol etmemiz ve değiştirmemiz gerekebilir.
- break: Matematiksel bir değeri bulana kadar işleme devam eden bir döngüye sahip olduğumuzu
varsayalım. Eğer bu döngüyü sonlandırmazsak, bu işlem bitene kadar devam etmesi gerekir. Peki
matematiksel sonucu elde edersek, döngüyü nasıl kıracağız? İşte bunu sağlayan komutun adı
break’tir.
- continue: break için verdiğimiz matematiksel hesaplama örneğinin aynısı continue komutu için de
geçerli olsun. Bu işlem devam ederken 10 adımlı bir algoritma çalıştırdığımızı varsayalım. İlk 3
matematiksel işlemin sonucunu biliyoruz. Eğer bu ilk 3 matematik işleminin sonucu hatalı ise,
sonraki 7 matematiksel işlemin bir önemi kalmayacaktır. Daha sonra, bu ilk 3 işlemden sonraki 7
işlemi yapmasını beklemek mantıklı mıdır? Bu durumda, döngüyü kırmadan sadece bu işlemden
vazgeçip döngünün başına dönülmesi, zaman ve kaynak yönetimi açısından daha mantıklıdır. İşte
bu döngüyü kırmadan döngünün başına dönmemizi sağlayan komutun adı continue’dur.
Bu iki komutu da tek bir uygulama içerisinde örnekleyerek nasıl çalıştığını inceleyeceğiz.
Örnek:
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
i := 0
cihanozhan.com
for {
fmt.Print("Enter value: ")
str, _ := reader.ReadString('n')
val, err := strconv.Atoi(strings.TrimSpace(str))
if err != nil {
fmt.Println("Beklenmeyen bir değer girildi. Başa dönülüyor.")
continue
}
if val == 3 {
fmt.Println("Döngü kırıldı!")
break
}
if val == 5 {
fmt.Println("Şartlar sağlanamadı. Döngünün başına dönüldü.")
continue
}
fmt.Println("index'in değeri: ", i)
i++
}
fmt.Println("Uygulamanın sonu.")
}
Örnek çıktısı:
Bu örneği çalıştırdığımızda, bizden nümerik bir değer girmemizi isteyecektir. Bu alan için eğer 3 değerini
girersek, döngü sonlanarak ekranda “Döngü kırıldı! Uygulamanın sonu." mesajını görürsünüz. Ancak eğer
uygulamaya 5 değerini girerseniz, uygulama bulunduğu konumdan başa dönerek akışı tekrar başlatır. Bu işlem
döngünün yeniden başladığı anlamına gelmez, sadece bir sonraki döngü sürecine geçilerek devam edilir.
Break/Continue - 1
Break/Continue - 2
cihanozhan.com
Ayrıca, yukarıdaki uygulamada küçük bir hata yönetimi işlemi de gerçekleştirdik. Bunun nedeni, gerçek bir
uygulama içerisindeki olası hata durumlarını örneklemek ve bu durumda neler yapılabileceğini anlamanızı
sağlamaktır. Örneğin, bu uygulamada kullanıcıdan bir sayısal değer istiyoruz. Ancak bu değeri öncelikle
metinsel veri(string) olarak alıyoruz. Ondan sonra da, geri planda bu metinsel veriyi sayıya çeviriyoruz. Eğer
kullanıcı veri girişi aşamasında gerçek bir sayı girmezse, bu uygulama çökecektir! İşte bu olası durumu
yönetebilmek için, veri dönüşümü gerçekleştirdiğimiz kısımdaki err hata nesnesini aktif ederek kullandık. Ve
eğer err nesnesi nil(null) değilse, bu işlem bir hata üretmiş demektir. Eğer uygulamada bir hata meydana gelirse,
uygulamanın continue ile başa dönerek devam etmesini sağladık.
Sonsuz Döngü
Programlamada bazı işlemlerin sürekli olarak yapılması gerekebilir. Örneğin, eğer bir bilgisayar ağından veri
okuma işlemi yapıyorsanız, bunu genellikle sürekli ve anlık olarak yapmalısınız. Bu işlemi yapabilmek için de,
ağ üzerindeki bir port’u anlık olarak dinleyen bir yazılım geliştirmelisiniz. Bu ve daha birçok kullanım amacı
için sonsuz döngüler oluşturulabilir.
Söz dizimi:
for {
}
Sonsuz döngü söz dizimi için basit bir örnek yapalım.
Örnek:
for {
fmt.Println("Merhaba Mars!")
}
Örnek çıktısı:
Bu işlemin sonucunda ekrana sürekli olarak “Merhaba Mars!” metni basılacaktır.
cihanozhan.com
Slice
Slice, Go programlama diline özgü, yeni bir programlama nesnesidir. Bir slice, arka planda dizileri kullanan ve
dizinin hafızadaki adresini işaret eden yeni bir dizi kullanım yöntemidir. Bir slice’ın kendisine ait veri tutma
yeteneği yoktur. Mevcut bir dizi üzerinden bir slice oluşturulabildiği gibi, bir slice’ı doğrudan da oluşturabiliriz.
Ancak doğrudan bir slice oluştursak bile, Go derleyicisi arka planda bu slice için bir dizi tanımlaması yapar ve
oluşturulan slice’ın işaretçisini bu dizinin hafıza adresine bağlar.
Not : Slice nesnesinin Türkçe karşılığı “dilim” olarak tanımlanır.
Bir slice oluşturmanın yöntemleri:
- Bir dizi üzerinden slice oluşturmak
- Bir diziden bağımsız olarak yeni bir slice oluşturmak
İlk olarak bir dizi üzerinde nasıl slice oluşturabileceğimizi inceleyelim.
Bir dizi üzerinde birden fazla slice oluşturulabilir. Bu oluşturulan slice’ların tümü tek bir dizinin hafızadaki
adresine bağlı olurlar. Eğer bir dizi üzerinde oluşturulan slice’lardan herhangi birisi üzerindeki elemanlarda bir
değişiklik yapılırsa, bu işlem doğrudan işaret edilen dizinin gerçek verisi üzerinde gerçekleştirilir. Bu nedenle,
herhangi bir slice’ta yapılan değişiklik, hem ana dizinin verisini, hem de bu dizi üzerinden üretilen tüm slice’ları
etkiler.
Örnek:
// Bir dizi tanımlıyoruz
numsArr := [5]float32{3.23, 4.56, 1.74, 76.94, 13.53}
Bir dizi ya da slice üzerinde, yeni bir slice oluşturmak için kullandığımız veriyi kesme yöntemi aşağıdaki
gibidir:
array|slice[baslangic:bitis]
Şimdi bu dizi üzerinde yeni bir slice oluşturalım.
slice1 := numsArr[:]
slice1 isimli slice’ımız numsArr dizisinin tüm verisini yansıtacak şekilde ayarlandı. Bunu sağlayan şey ise [:]
tanımıdır. Bu işlemin aynısını numsArr[0:] yöntemiyle de elde edebilirsiniz.
Oluşturulan slice verisini ekrana bastırmak için:
fmt.Println(sliceName)
Yukarıdaki söz diziminde bulunan start alanı, veri kesme işleminin hangi index’ten başlayacağın, end alanı ise
bu kesme işleminin hangi index’e kadar olan veriyi kapsayacağını belirtmek için kullanılır.
slice1 isimli slice’ı oluştururken start ve end alanlarını boş bıraktık. Bunun anlamı, herhangi bir limit olmadan
tüm veriyi yeni slice’a istiyoruz demektir.
numsArr dizisindeki 4.56 ondalıklı değerinin indexi bir(1)’dir. Sadece bu veriyi alacak bir slice oluşturmak
istersek şu şekilde yapabiliriz.
slice2 := numsArr[1:2] // sonuç: [4.56]
cihanozhan.com
Not : Dizilerdeki index’leme mantığını iyi bilen bir geliştirici için slice’lar üzerinde çalışmak çok kolaydır.
Diğer bir örnek olarak, dizi elemanlarının ilki hariç, geri kalan tüm elemanları alarak yeni bir slice oluşturalım.
slice3 := numsArr[1:]
Veri kesme alanında dinamik bir belirteç de kullanabiliriz.
Örneğin, numsArr dizisinin toplam eleman uzunluğunun 2 eksiği kadar bir elemanı elde edelim.
Örnek:
slice4 := numsArr[:len(numsArr)-2]
Örnek çıktısı:
[3.23 4.56 1.74]
Not : Yukarıdaki örnekte kullandığımız len(arrayName) fonksiyonu ile bir dizi ya da slice’ın elemanlarının
toplamını elde edebiliyoruz.
Uygulama Ödevi : Yukarıdaki gibi bir dinamik veri kesme yöntemini cap() fonksiyonuyla uygulayınız.
Şu ana kadar mevcut bir dizi üzerinden nasıl slice oluşturabileceğimizi ve çeşitli veri kesme yöntemlerini
inceledik. Şimdi de bir slice nesnesini herhangi bir diziden bağımsız olarak nasıl oluşturabileceğimize bakalım.
Bir Diziden Bağımsız Olarak Yeni Bir Slice Oluşturmak
Go dili yazılım geliştiricilerinin slice’lar ile olabildiğince esnek çalışabilmelerini sağlamak için slice’lara birçok
özellik ve esneklik eklemiştir. Bunlardan biri de, slice’ların dizilerden bağımsız olarak kullanılabilmesidir. Bu
konuya teknik olarak bakacak olursak, aslında slice’ın bilgisayar belleğinde veri depolayabilmek için dizilere
ihtiyaç duyar. Bu nedenle, biz yeni bir slice oluşturduğumuzda, Go derleyicisi arka planda bu slice için bir dizi
oluşturarak, slice’ları bağımsız şekilde kullanabilmemize izin vermektedir.
Şimdi bu yöntemi uygulayarak yeni bir slice oluşturalım.
Örnek:
Uygulayacağımız örnek mevsimler ve aylar ile ilgili olacak. Yeni bir slice oluşturacağız ve yılın 12 ayını bu
slice’a ekleyeceğiz. Sonrasında bu slice üzerinden farklı slice’lar oluşturarak bu ayları mevsimlere göre
ayıracağız.
months := [...]string{
1: "Ocak",
2: "Şubat",
3: "Mart",
4: "Nisan",
5: "Mayıs",
6: "Haziran",
7: "Temmuz",
8: "Ağustos",
9: "Eylül",
10: "Ekim",
cihanozhan.com
11: "Kasım",
12: "Aralık"}
Not : months dizişi 13 eleman kapasitesine sahiptir(cap/len(months) ile kontrol edin). Ancak biz ay
numaralandırmasını bir(1)’den başlatabilmek için sıfırıncı(0) index’i kullanmadık. Bu sayede, daha kolay
okunabilir ve yönetilebilir bir slice’a sahip olduk.
Yukarıdaki months slice’ını oluştururken köşeli parantezler içerisinde üç nokta kullandık([…]). Bunun nedeni,
yeni slice’ımızın kapasitesini, başlangıçtaki atanan elemanların dinamik olarak belirlemesini sağlamaktı.
Not : Bu örnekte kullanılacak eleman sayısı sabit olduğu için burada sabit bir değer de kullanabilirsiniz.
Ayları mevsimlere ayırma uygulamamıza adım adım devam ederken, şimdi 12 ay verisini üçerli gruplardan
oluşacak şekilde 4 mevsime bölelim. Bu işlemi birinci aydan onikinci aya kadar olacak şekilde baştan başlayarak
yapacağız.
p1 := months[1:4] // Ocak, Şubat, Mart
p2 := months[4:7] // Nisan, Mayıs, Haziran
p3 := months[7:10] // Temmuz, Ağustos, Eylül
p4 := months[10:13] // Ekim, Kasım, Aralık
Not : p1, p2 şeklinde p ile başlayan isimlendirmenin açılımı part’tır.
Yılın ilkbahar aylarını, spring adında bir slice oluşturarak ayıralım.
spring := p1[2:3] // 3. ayı ilkbahara ait olduğu için aldık
springSub := p2[0:2] // 4. ve 5. ayları ilkbahara ait oldukları için aldık
for _, month := range springSub {
spring = append(spring, month)
}
fmt.Println("İlkbahar: ", spring)
İlkbahar aylarının çıktısı:
İlkbahar: [Mart Nisan Mayıs]
Yılın yaz aylarını, summer adında bir slice oluşturarak ayıralım.
summer := p2[2:3] // 6. ayı yaza ait olduğu için aldık
summerSub := p3[0:2] // 7. ve 8. ayları yaza ait oldukları için aldık
for _, month := range summerSub {
summer = append(summer, month)
}
fmt.Println("Yaz: ", summer)
Yaz aylarının çıktısı:
Yaz: [Haziran Temmuz Ağustos]
Yılın sonbahar aylarını autumn adında bir slice oluşturarak ayıralım.
autumn := p3[2:3] // 9. ayı sonbahara ait olduğu için aldık
autumnSub := p4[0:2] // 10. ve 11. ayları sonbahara ait oldukları için aldık
for _, month := range autumnSub {
cihanozhan.com
autumn = append(autumn, month)
}
fmt.Println("Sonbahar: ", autumn)
Sonbahar aylarının çıktısı:
Sonbahar: [Eylül Ekim Kasım]
Yılın kış aylarını winter adında bir slice oluşturarak ayıralım.
winter := p4[2:3] // Yılın son ayı kışa ait olduğu için aldık
winterSub := p1[0:2] // Yılın ilk iki ayı kışa ait olduğu için aldık
for _, month := range winterSub {
winter = append(winter, month)
}
fmt.Println("Kış: ", winter)
Kış aylarının çıktısı:
Kış: [Aralık Ocak Şubat]
Yılın aylarını mevsimlere göre ayırma uygulamamızı tamamladık. Artık ilgili slice’ları istediğiniz gibi
kullanarak mevsimlere göre işlemler yapabilirsiniz. Ancak, sanki biraz uzun bir kodlama oldu gibi! Mesela her
işlem için ayrı ayrı for döngüsü oluşturarak slice’ları birbiriyle birleştirdik. Aslında bu işlem yerine bir metot
oluşturarak 4 farklı işlem için tek bir metot kullanabilirdik. Bu bir yöntemdi… Ancak henüz metotları
incelemedik ve metotların önemini anlamak için bu tür sorunları yaşamak gerekiyor! Merak etmeyin! Başka bir
yöntem daha mevcut! Şimdi bunu yeni yöntemi summer slice’ı için yaptığımız örneğin alternatifi olarak
yapalım.
Kısa Kod: Yılın yaz aylarını summer adında bir slice oluşturarak ayıralım.
spring := p1[2:3]
springSub := p2[0:2]
// for döngüsü ile yaptığımız işlemin aynısını tek başına yapan kod!
summer = append(summer, summerSub...)
Kıssadan Hisse : Eğer kullandığınız programlama dili ve platformu iyi tanımazsanız, bu örnekte olduğu gibi
daha fazla kod yazmanız gerekebilir ve hatta bazen çözümsüz kalabilirsiniz.
İki Slice İçerisindeki Kesişen Verileri Bulmak
Gerçek dünya uygulamaları geliştirirken slice’lar ile çok sık oynamanız gerekecek. Biz de gerçek bir ihtiyaçtan
yola çıkarak, küçük bir kesişen verileri bulma uygulaması yaparak slice’lar ile oynayalım.
Bazı isimler sadece erkek çocukları için, bazıları sadece kız çocukları için kullanılır. Ancak bazı isimler unisex
olarak tanımlanırlar. Yani, bu isimleri hem erkek çocukları hem de kız çocukları kullanabilir. Biz de elimizdeki
veri seti üzerinde unisex isimleri bulmak için küçük bir algoritma çalıştıracağız. Bu uygulamayı gerçek dünya
uygulaması haline getirmek de mümkündür. Sadece elinizde Türk unisex isimleri listesinin olması yeterlidir.
Örnek:
girlNames := [4]string{"Ayşe", "Fatma", "Doğa", "Deniz"}
boyNames := [4]string{"Kadir", "Ahmet", "Deniz", "Doğa"}
cihanozhan.com
unisexName := ""
for _, girlName := range girlNames {
for _, boyName := range boyNames {
if girlName == boyName {
unisexName = girlName
fmt.Printf("%s unisex bir isimdir.n", unisexName)
}
}
}
Örnek çıktısı:
Doğa unisex bir isimdir.
Deniz unisex bir isimdir.
Bir Slice Üzerindeki Verilerde Değişiklik Yapmak
Bilgisayar hafızası üzerindeki verilerde hızlı bir şekilde değişiklikler yapabilmek önemlidir. Örneğin, bir slice’da
bulunan verilerde çok fazla kod yazmadan değişiklikler yapabiliriz.
Sorun : Elimizde 10 adetlik bir kullanıcı listesi var. Bu kullanıcı listesindeki kullanıcıların son 5 tanesinin yaş
bilgisi sisteme yanlış girilmiş. Bu 5 kullanıcıyı bulup, yaş bilgilerinin bir artırılması gerekiyor.
Örnek:
ages := [...]int{32, 43, 18, 54, 22, 21, 34, 19, 59, 36}
changeThat := ages[5:10]
fmt.Println("Verinin İlk Hali: ", ages)
for i := range changeThat {
changeThat[i]++
}
fmt.Println("Verinin Son Hali: ", ages)
Örnek sonucu:
Verinin İlk Hali: [32 43 18 54 22 21 34 19 59 36]
Verinin Son Hali: [32 43 18 54 22 22 35 20 60 37]
Çok Boyutlu Slice Kullanımı
Diziler konusundan hatırlayacağınız çok boyutlu çalışabilme yeteneğini bir slice üzerinde de uygulayabiliriz.
Şimdi, çok boyutlu slice’lar ile nasıl çalışabileceğimize bir bakalım.
Örnek:
programmingLanguages := [][]string{
{"C", "C++"},
{"C#", "Java"},
{"JavaScript", "Rust"},
{"Go", "Erlang"},
cihanozhan.com
}
for _, loop1 := range programmingLanguages {
for _, loop2 := range loop1 {
fmt.Printf("%s ", loop2)
}
fmt.Printf("n")
}
Örnek sonucu:
C C++
C# Java
JavaScript Rust
Go Erlang
Bir Slice’ın Nil Durumunu Kontrol Etmek
Go dilinde nesnelerin null olma durumu nil ile yönetilir. Ve her slice’ın başlangıç değeri varsayılan olarak
nil’dir. Eğer bir slice’ın başlangıcında değer aldığını algoritmik olarak garanti edemiyorsak, o zaman slice için
bir nil kontrolü yapmalıyız.
Not : Go dilinde hata yönetimini “Hata Yönetimi” bölümünde derinlemesine inceleyeceğiz. Ancak yeri
gelmişken, slice ile ilgili küçük bir bilgi notu olarak bu eklemeyi yapmayı uygun gördük.
Örnek:
var names []string
if names == nil {
names = append(names, "Cihan", "Barış", "Erdal")
fmt.Println("İsimler: ", names)
}
Örnek sonucu:
İsimler: []
İsimler: [Cihan Barış Erdal]
Yukarıdaki işlem gayet basittir. Slice’ı if ile kontrol ederek nil olup olmadığına bakıyoruz. Eğer slice’ın değer
durumu nil ise if scope’u içerisinde slice’a değer ekliyoruz.
cihanozhan.com
Map
Map nesneleri, Go dilindeki unordered key/value pair koleksiyonlardır. Her Map nesnesinin key ve value
alanları bulunur. Key/value pair nesne modelinin yapısı gereği, key alanları benzersiz bir anahtar içermelidir.
Value alanları ise herhangi bir veri yapısında olabilir. Bir Map nesnesini oluşturmak için make() fonksiyonu
kullanılır. Map nesnelerinin başlangıç değerleri nil’dir. Bir Map nesnesinin key ve value alanları farklı veri
tiplerine sahip olabilir.
Map Kullanımı
İlk örneğimizde key ve value alanlarının ikisini de string veri tipiyle tanımlayan bir örnek yapacağız.
Örnek:
states := make(map[string]string) // Map nesnesini oluştur
fmt.Println("Boş : ", states) // nil değere sahip map nesnesini ekrana bas
Örnek çıktısı:
Boş : map[]
Şimdi de oluşturduğumuz states isimli Map nesnesine birkaç şehir verisi ekleyelim.
Örnek:
states["IST"] = "İstanbul" // Benzersiz olan IST anahtarına Istanbul verisini ekler
states["ANK"] = "Ankara"
states["ANT"] = "Antalya"
fmt.Println("Dolu : ", states)
Örnek çıktısı:
Dolu : map[IST:İstanbul ANK:Ankara ANT:Antalya]
Bir Map’in Elemanlarına Erişim
Oluşturduğumuz states adındaki Map nesnesinin bir elemanına erişelim.
Örnek:
antalya := states["ANT"]
fmt.Println("Seçili Şehir : ", antalya)
Map’in bir elemanına erişmek için mapName[key] yapısını kullanmak yeterlidir.
Örnek çıktısı:
Seçili Şehir : Antalya
Bir Map Nesnesinden Eleman Silmek
Map nesnesinden eleman silmek için Go’nun built-in fonksiyonlarından delete()’i kullanıyoruz.
Örnek:
delete(states, "ANK")
cihanozhan.com
fmt.Println(states)
Örnek çıktısı:
map[IST:İstanbul ANT:Antalya]
Döngü ile Map Verisine Erişim
Map nesneleri genellikle birden fazla veriye sahip oldukları için, bu nesne üzerinde iteration(yineleme) işlemleri
uygulamak önemlidir. Şimdi bir Map nesnesini döngü ile nasıl kullanabileceğimize bakalım.
Öncelikle, states nesnesinin eleman adedini artırmak için bir eleman daha ekliyoruz.
states["ERZ"] = "Erzurum"
Örnek:
for key, value := range states {
fmt.Printf("%v: %vn", key, value)
}
Örnek çıktısı:
IST: İstanbul
ERZ: Erzurum
ANT: Antalya
Yukarıdaki döngü işleminde states isimli Map üzerinden key ve value değerlerini alarak ekrana yazdırdık.
Burada kullandığımız key ve value tanımlamaları kodun anlaşılması için tercih edilen isimlerdir. Bu alanlar için
istediğiniz isimlendirmeyi kullanabilirsiniz. Ayrıca bazı durumlarda sadece value değerlerini elde etmek
isteyebilirsiniz. Bu tür durumlarda key yerine altçizgi( _ ) kullanarak sadece value nesnesine erişmek istediğinizi
derleyiciye bildirmiş olursunuz. Aynı kural value nesnesi için de geçerlidir.
for _, value := range states
ya da
for key, _ := range states
Şimdi de, gene döngüleri kullanarak Map nesnesi üzerinde farklı bir işlem yapalım.
İstek: states isimli Map nesnesinin eleman sayısı kapasitesine sahip bir key list oluşturun.
Örnek:
keys := make([]string, len(states))
i := 0
for k := range states {
keys[i] = k
i++
}
fmt.Println(keys)
cihanozhan.com
Örnek çıktısı:
[ANT IST ERZ]
Peki bu key listesini alfabetik olarak sıralayabilir miyiz?
Sıralama işlemi Go built-in paketlerinden sort ile çok kolay…
Örnek:
sort.Strings(keys)
Örnek çıktısı:
[ANT ERZ IST]
Sıraladığımız key’lerin index değerlerine göre states nesnesindeki şehirleri yazdıralım.
Örnek:
for i := range keys {
fmt.Println(states[keys[i]])
}
Örnek çıktısı:
Antalya
Erzurum
İstanbul
Map İçerisindeki Bir Elemanın Varlığını Kontrol Etmek
Bazı durumlarda eldeki veriyi koleksiyon nesnelerindeki verileri karşılaştırarak verinin varlığını kontrol etmek
gerekebilir. Bu tür işlemler, normal arama ve bulma fonksiyonlarıyla yapılırken çok maliyetli olabilir. Ancak
key/value pair koleksiyon modelinde bu tür bir işlemi key üzerinden düşük maliyet ile yapabilmekteyiz.
Örnek:
state, ok := states["ANK"]
if !ok {
fmt.Println("Aranan veri bulunamadı!")
return
}
fmt.Println(state)
Yukarıdaki örnekte, states isimli Map nesnesinin ANK adında bir key’e sahip olup olmadığını kontrol ediyoruz.
Eğer bu Map nesnesi ANK isimli bir key’e sahipse, sol kısımda tanımladığımız ok değişkenine true değerini,
state değişkenine de eşleşen key’in value değerini dönecektir. Eğer bu eşleşme gerçekleşmezse, ok değişkenine
false değerini dönecektir.
Örnek sonucu:
Ankara
Yukarıdaki işlemde states içerisinde olmayan bir veriyi kontrol etmeyi deneyin. Ekrana “Aranan veri
bulunamadı.” mesajı basılacak ve hemen altındaki return komutu ile de işlem sonlandırılacaktır.
cihanozhan.com
Bu yöntemin daha doğru kullanımı şu şekildedir:
Örnek:
state, ok := states["ANK"]
if ok {
fmt.Println(state)
}
Yani, eğer Map içerisinde ANK ile eşleşen bir eleman varsa bunu ekrana bas, yoksa herhangi bir şey yapmana
gerek yoktur.
type Anahtar Kelimesi
Daha önce, Go dilinin yazılım geliştirme süreçlerindeki sıkıntılara odaklandığını belirtmiştik. type anahtar
kelimesi de, bu tür sorunlardan birine çözüm olmak için dile eklenen bir özelliktir. En temel anlamda
düşünürsek, Go kod dosyalarınızda tanımladığınız değişkenlerdeki kompozit(composite) tipleri sonradan
değiştirmek(redeclare) gibi süreçler baş ağrıtıcı olabilir. Bu nedenle, bu tür tipleri tanımlarken type anahtar
kelimesini kullanmak, sonradan revize etme gibi işlemlerde işinizi kolaylaştırabilir. Biraz karmaşık gibi görünse
de, bu konuyu örneklerle inceleyeceğiz.
Söz dizimi: Tekli
type typeName underlying-type
Söz dizimi: Çoklu
type (
typeName1 sourceType1
typeName2 sourceType2
)
type ile ilgili temel tanımlar:
- Yeni tanımlanan tip(typeName1 gibi) ile, onun altında yatan sourceType1(int gibi) tipleri aynıdır.
- Aynı alt tipler ile tanımlanan tipler birbirlerine dönüştürülebilir.
- type ile oluşturulacak tipler fonksiyonların gövdesinde tanımlanabilir.
type Kullanımı
Genel olarak type anahtar kelimesinin amacını anladığımıza göre, şimdi type ve farklı birçok veri tipini
kullanarak oluşturacağımız örnekleri inceleyebiliriz.
type ile kullanabileceğimiz bazı Go dili nesnelerini henüz incelemedik. Ancak type ile neler yapılabileceğini
anlamak adına bu örnekleri de bu başlık altında görebileceksiniz.
type anahtar kelimesinin en temel kullanımı şu şekildedir:
type Age int
Bu basit tanımlamada Age adında bir tip oluşturarak bu tipin arka planda bir integer ile temsil edileceğini
belirtmiş olduk. Bunun anlamı, Age’in veri tipi de kapasitesi de integer ile aynıdır.
type kullanımına çoklu tanımlama örneği olarak ise:
cihanozhan.com
type (
Name string
Age int
)
Bu tanımlama yönteminin temel amacı, birden fazla type nesnesinin dağınık olarak oluşturulmaktansa, daha
okunabilir ve düzenli olmasını sağlayacak şekilde bir arada tanımlanmasını sağlamaktır. Çoklu type bloğu
içerisinde farklı veri tiplerine sahip birden fazla type nesnesi oluşturabilirsiniz.
Şimdi type anahtar kelimesinin farklı tipler ile nasıl kullanılabileceğine bir göz atalım.
type anahtar kelimesini bir sonraki bölümde inceleyeceğimiz struct nesneleriyle birlikte de sık sık kullanacağız.
Buna da basit bir örnek verebiliriz:
Örnek:
type Video struct {
ID, Time int
Trainer, Title string
}
type anahtar kelimesini gene sonraki bölümlerde inceleyeceğimiz fonksiyonlar ile birlikte de kullanabileceğiz.
Örnek:
type Convert func(inputFile int, isFast bool)
(convertedFilePath string, err error)
type anahtar kelimesini daha önceki bölümlerde incelediğimiz dizi ve slice nesneleriyle birlikte de kullanabiliriz.
Go dili bu konuda çok esnek ve çeşitliliğe sahiptir. Hatırlarsanız, değişken ve nesne tanımlamada var adında bir
tanımlayıcı ve özel bir var scope’una sahiptik. Aynı şekilde var ile tanımlayabildiğimiz bu nesneleri type ile de
tanımlayabiliyoruz.
Örnek: Dizi için…
type Articles [5]string
Örnek: Slice için…
type Comments []string
Tanımlı Tipler & Tanımlanmamış Tipler
Go 1.9 versiyonu öncesinde tip tanımlaması üzerinde herhangi bir ayrım yapmamıza gerek yoktu. Ancak Go
1.9’dan sonra eklenen yeni kullanım yöntemiyle birlikte bir ayrım yapmamız gerekiyor.
Go 1.9 öncesinde kullandığımız yönteme zaten tanımlı tipler diyorduk. Go 1.9 sonrasında ise tanımsız(non-
defined type) diyebileceğimiz yeni bir kullanım yöntemi eklendi.
Şimdi bir alias tip oluşturarak tanımsız tiplere örnek verelim.
cihanozhan.com
Örnek:
type (
ID = int
Name = string
)
Yukarıdaki alias tipi kullanımının diğer kullanımdan farkı, tanımlayıcı isim ile veri tipi arasındaki eşittir(=)
işaretidir. Bu nedenle, eğer alias tipi olarak bir type tanımlayacaksanız aradaki eşittir(=) işaretini koymayı
unutmamalısınız.
Peki bu yöntemi nasıl ve neden kullanırız?
Örnek:
Kullanıcının adını ve veritabanındaki ID bilgisini tutacak bir Map değişkeni oluşturmak istediğimizi düşünelim.
Bu örnek aşağıdaki gibi olabilirdi:
type users = map[string]int
Kullanıcının isim bilgilerini users adındaki Map nesnesinin değer alanında, kullanıcının ID bilgilerini ise key
alanında tutabiliriz. Peki bu kullanımı biraz daha kullanıcılar verisinin yapısına göre tasarlamak istersek?
type users = map[Name]ID
Sanırım son oluşturduğumuz users Map nesnesinin biraz daha açık ve kullanıcı verisine göre özelleştirilmiş
olduğu konusunda hemfikiriz.
Şimdi tanımlı ve tanımsız tipleri karşılaştırarak bu konuyu sonlandıralım.
Örnek:
type Tip1 []string // Tip1 tanımlı tiptir.
type Tip2 = Tip1 // Tip2 nesnesi Tip1 nesnesiyle eşitlendi!
// Bu nedenle Tip2'de tanımlı bir tiptir.
type Tip3 = []string // Alias type(Tip3) ve []string tanımsız tiptir.
type Dönüştürme
type anahtar kelimesini tanımlarken, aynı alt veri tipine sahip type tiplerinin birbirlerine
dönüştürülebileceğinden bahsetmiştik. Şimdi bunu nasıl yapabileceğimize bir bakalım.
Örnek: Hatalı!
type age int16
var newAge int16 = 27
var UserAge age = newAge
Yukarıdaki örnekteki ilk satırda, int16 veri tipine sahip age adında bir tip oluşturduk. İkinci satırda ise, newAge
adında ve int16 veri tipine sahip bir değişken oluşturduk ve bu değişkene 27 değerini atadık. Üçüncü ve son
satırda ise, yeni oluşturduğumuz UserAge adındaki bir değişkene veri tipi olarak ilk satırda oluşturduğumuz age
adındaki tipi atadık. Ve bu UserAge değişkenine, age tipiyle aynı veri tipine sahip olan newAge değişkenini
atadık.
cihanozhan.com
Yukarıdaki örneği çalıştırmanıza gerek kalmadan hata verdiğini ve VSCode editörünün hatalı kodun altını
kırmızıyla çizdiğini görebilirsiniz. Bunun nedeni, age tipi ile newAge değişkenlerinin aynı veri tipine(int16)
sahip olsalar bile, derleyici tarafından karıştırılmasıdır. Derleyici bu iki nesnenin de aynı tipe sahip olduğunu
bilse bile, bu nesneleri birbirine atayabilmek için explicit conversion işlemi uygulanmasını şart koşuyor. Yani,
bu tipleri birbirine atamak istediğimizi özel olarak belirtmemiz gerekiyor. Peki nasıl?
Örnek:
type age int16
var newAge int16 = 27
var UserAge age = age(newAge)
Yukarıdaki örneği çalıştırdığınızda ekrana 27 değerinin basıldığını görebilirsiniz. Dikkat ederseniz, son
örneğimizin diğer örnekten tek farkı newAge değişkeni üzerinde uygulanan age tipine dönüştürme işlemidir. Bu
dönüştürmeyi de açık bir şekilde age(newAge) diyerek gerçekleştirdik.
cihanozhan.com
cihanozhan.com

Contenu connexe

Tendances

Git with bitbucket
Git with bitbucketGit with bitbucket
Git with bitbucketSumin Byeon
 
Continuous Integration/Deployment with Gitlab CI
Continuous Integration/Deployment with Gitlab CIContinuous Integration/Deployment with Gitlab CI
Continuous Integration/Deployment with Gitlab CIDavid Hahn
 
Jenkins Pipeline Tutorial | Jenkins Build And Delivery Pipeline | Jenkins Tut...
Jenkins Pipeline Tutorial | Jenkins Build And Delivery Pipeline | Jenkins Tut...Jenkins Pipeline Tutorial | Jenkins Build And Delivery Pipeline | Jenkins Tut...
Jenkins Pipeline Tutorial | Jenkins Build And Delivery Pipeline | Jenkins Tut...Simplilearn
 
A Git Workflow Model or Branching Strategy
A Git Workflow Model or Branching StrategyA Git Workflow Model or Branching Strategy
A Git Workflow Model or Branching StrategyVivek Parihar
 
Gradle - the Enterprise Automation Tool
Gradle  - the Enterprise Automation ToolGradle  - the Enterprise Automation Tool
Gradle - the Enterprise Automation ToolIzzet Mustafaiev
 
Intro to git and git hub
Intro to git and git hubIntro to git and git hub
Intro to git and git hubJasleenSondhi
 
Container based CI/CD on GitHub Actions
Container based CI/CD on GitHub ActionsContainer based CI/CD on GitHub Actions
Container based CI/CD on GitHub ActionsCasey Lee
 
Treinamento git - Papos RBSDev
Treinamento git - Papos RBSDevTreinamento git - Papos RBSDev
Treinamento git - Papos RBSDevHélio Medeiros
 
Argo Workflows 3.0, a detailed look at what’s new from the Argo Team
Argo Workflows 3.0, a detailed look at what’s new from the Argo TeamArgo Workflows 3.0, a detailed look at what’s new from the Argo Team
Argo Workflows 3.0, a detailed look at what’s new from the Argo TeamLibbySchulze
 
Infrastructure as Code
Infrastructure as CodeInfrastructure as Code
Infrastructure as CodeRobert Greiner
 
Using GitLab CI
Using GitLab CIUsing GitLab CI
Using GitLab CIColCh
 

Tendances (20)

BitBucket presentation
BitBucket presentationBitBucket presentation
BitBucket presentation
 
Git with bitbucket
Git with bitbucketGit with bitbucket
Git with bitbucket
 
Continuous Integration/Deployment with Gitlab CI
Continuous Integration/Deployment with Gitlab CIContinuous Integration/Deployment with Gitlab CI
Continuous Integration/Deployment with Gitlab CI
 
Git and Github Session
Git and Github SessionGit and Github Session
Git and Github Session
 
Go lang
Go langGo lang
Go lang
 
CI/CD with Github Actions
CI/CD with Github ActionsCI/CD with Github Actions
CI/CD with Github Actions
 
Jenkins Pipeline Tutorial | Jenkins Build And Delivery Pipeline | Jenkins Tut...
Jenkins Pipeline Tutorial | Jenkins Build And Delivery Pipeline | Jenkins Tut...Jenkins Pipeline Tutorial | Jenkins Build And Delivery Pipeline | Jenkins Tut...
Jenkins Pipeline Tutorial | Jenkins Build And Delivery Pipeline | Jenkins Tut...
 
A Git Workflow Model or Branching Strategy
A Git Workflow Model or Branching StrategyA Git Workflow Model or Branching Strategy
A Git Workflow Model or Branching Strategy
 
Gitlab ci-cd
Gitlab ci-cdGitlab ci-cd
Gitlab ci-cd
 
Devops
DevopsDevops
Devops
 
Gradle - the Enterprise Automation Tool
Gradle  - the Enterprise Automation ToolGradle  - the Enterprise Automation Tool
Gradle - the Enterprise Automation Tool
 
Intro to git and git hub
Intro to git and git hubIntro to git and git hub
Intro to git and git hub
 
Gradle Introduction
Gradle IntroductionGradle Introduction
Gradle Introduction
 
Container based CI/CD on GitHub Actions
Container based CI/CD on GitHub ActionsContainer based CI/CD on GitHub Actions
Container based CI/CD on GitHub Actions
 
Treinamento git - Papos RBSDev
Treinamento git - Papos RBSDevTreinamento git - Papos RBSDev
Treinamento git - Papos RBSDev
 
Argo Workflows 3.0, a detailed look at what’s new from the Argo Team
Argo Workflows 3.0, a detailed look at what’s new from the Argo TeamArgo Workflows 3.0, a detailed look at what’s new from the Argo Team
Argo Workflows 3.0, a detailed look at what’s new from the Argo Team
 
Infrastructure as Code
Infrastructure as CodeInfrastructure as Code
Infrastructure as Code
 
Using GitLab CI
Using GitLab CIUsing GitLab CI
Using GitLab CI
 
Haskell
HaskellHaskell
Haskell
 
Git basic
Git basicGit basic
Git basic
 

Similaire à Golang Book - Go Programlama Dili Temelleri

Similaire à Golang Book - Go Programlama Dili Temelleri (19)

Delphi xe5
Delphi xe5Delphi xe5
Delphi xe5
 
Delphi xe5
Delphi xe5Delphi xe5
Delphi xe5
 
Fonksiyonlar
FonksiyonlarFonksiyonlar
Fonksiyonlar
 
C goto
C gotoC goto
C goto
 
Phyton Programlama Dili
Phyton Programlama DiliPhyton Programlama Dili
Phyton Programlama Dili
 
Kabuk programlama 2
Kabuk programlama 2Kabuk programlama 2
Kabuk programlama 2
 
Delphi Menu
Delphi MenuDelphi Menu
Delphi Menu
 
Menüler
MenülerMenüler
Menüler
 
Templates
Templates Templates
Templates
 
Ileri seviye javascript by Azer Koculu
Ileri seviye javascript by Azer KoculuIleri seviye javascript by Azer Koculu
Ileri seviye javascript by Azer Koculu
 
Regular expression
Regular expressionRegular expression
Regular expression
 
Programlama Temelleri Hazır Metodlar
Programlama Temelleri Hazır MetodlarProgramlama Temelleri Hazır Metodlar
Programlama Temelleri Hazır Metodlar
 
Roket Yazılımı Eğitimi Hafta 1
Roket Yazılımı Eğitimi Hafta 1Roket Yazılımı Eğitimi Hafta 1
Roket Yazılımı Eğitimi Hafta 1
 
Program ingilizcesi
Program ingilizcesiProgram ingilizcesi
Program ingilizcesi
 
php nin yapı taşları
php nin yapı taşlarıphp nin yapı taşları
php nin yapı taşları
 
C programlama
C programlamaC programlama
C programlama
 
Python for Hackers
Python for HackersPython for Hackers
Python for Hackers
 
Fann tool kılavuzu
Fann tool kılavuzuFann tool kılavuzu
Fann tool kılavuzu
 
Introduction to BASH and Terminal
Introduction to BASH and TerminalIntroduction to BASH and Terminal
Introduction to BASH and Terminal
 

Plus de Cihan Özhan

MongoDB - NoSQL Overview
MongoDB - NoSQL OverviewMongoDB - NoSQL Overview
MongoDB - NoSQL OverviewCihan Özhan
 
MongoDB - JSON'a Genel Bakış
MongoDB - JSON'a Genel BakışMongoDB - JSON'a Genel Bakış
MongoDB - JSON'a Genel BakışCihan Özhan
 
AI and Machine Learning - Today’s Implementation Realities
AI and Machine Learning - Today’s Implementation RealitiesAI and Machine Learning - Today’s Implementation Realities
AI and Machine Learning - Today’s Implementation RealitiesCihan Özhan
 
Mobil Uygulama Güvenliği (Mobile Security)
Mobil Uygulama Güvenliği (Mobile Security)Mobil Uygulama Güvenliği (Mobile Security)
Mobil Uygulama Güvenliği (Mobile Security)Cihan Özhan
 
Blockchain : Decentralized Application Development (Turkish)
Blockchain : Decentralized Application Development (Turkish)Blockchain : Decentralized Application Development (Turkish)
Blockchain : Decentralized Application Development (Turkish)Cihan Özhan
 
Golang Book - Genel Bakış
Golang Book - Genel BakışGolang Book - Genel Bakış
Golang Book - Genel BakışCihan Özhan
 
MLaaS - Presenting & Scaling Machine Learning Models as Microservices
MLaaS - Presenting & Scaling Machine Learning Models as MicroservicesMLaaS - Presenting & Scaling Machine Learning Models as Microservices
MLaaS - Presenting & Scaling Machine Learning Models as MicroservicesCihan Özhan
 
Yapay Zeka Güvenliği : Machine Learning & Deep Learning & Computer Vision Sec...
Yapay Zeka Güvenliği : Machine Learning & Deep Learning & Computer Vision Sec...Yapay Zeka Güvenliği : Machine Learning & Deep Learning & Computer Vision Sec...
Yapay Zeka Güvenliği : Machine Learning & Deep Learning & Computer Vision Sec...Cihan Özhan
 
Endüstriyel Yapay Zeka ve Otonom Sistemler
Endüstriyel Yapay Zeka ve Otonom SistemlerEndüstriyel Yapay Zeka ve Otonom Sistemler
Endüstriyel Yapay Zeka ve Otonom SistemlerCihan Özhan
 
AI Security : Machine Learning, Deep Learning and Computer Vision Security
AI Security : Machine Learning, Deep Learning and Computer Vision SecurityAI Security : Machine Learning, Deep Learning and Computer Vision Security
AI Security : Machine Learning, Deep Learning and Computer Vision SecurityCihan Özhan
 
Yapay Zeka Güvenliği : Machine Learning & Deep Learning & Computer Vision Sec...
Yapay Zeka Güvenliği : Machine Learning & Deep Learning & Computer Vision Sec...Yapay Zeka Güvenliği : Machine Learning & Deep Learning & Computer Vision Sec...
Yapay Zeka Güvenliği : Machine Learning & Deep Learning & Computer Vision Sec...Cihan Özhan
 
Python Programlama Dili
Python Programlama DiliPython Programlama Dili
Python Programlama DiliCihan Özhan
 
İleri Seviye T-SQL Programlama - Chapter 21
İleri Seviye T-SQL Programlama - Chapter 21İleri Seviye T-SQL Programlama - Chapter 21
İleri Seviye T-SQL Programlama - Chapter 21Cihan Özhan
 
İleri Seviye T-SQL Programlama - Chapter 20
İleri Seviye T-SQL Programlama - Chapter 20İleri Seviye T-SQL Programlama - Chapter 20
İleri Seviye T-SQL Programlama - Chapter 20Cihan Özhan
 
İleri Seviye T-SQL Programlama - Chapter 19
İleri Seviye T-SQL Programlama - Chapter 19İleri Seviye T-SQL Programlama - Chapter 19
İleri Seviye T-SQL Programlama - Chapter 19Cihan Özhan
 
İleri Seviye T-SQL Programlama - Chapter 18
İleri Seviye T-SQL Programlama - Chapter 18İleri Seviye T-SQL Programlama - Chapter 18
İleri Seviye T-SQL Programlama - Chapter 18Cihan Özhan
 
İleri Seviye T-SQL Programlama - Chapter 17
İleri Seviye T-SQL Programlama - Chapter 17İleri Seviye T-SQL Programlama - Chapter 17
İleri Seviye T-SQL Programlama - Chapter 17Cihan Özhan
 
İleri Seviye T-SQL Programlama - Chapter 16
İleri Seviye T-SQL Programlama - Chapter 16İleri Seviye T-SQL Programlama - Chapter 16
İleri Seviye T-SQL Programlama - Chapter 16Cihan Özhan
 
İleri Seviye T-SQL Programlama - Chapter 15
İleri Seviye T-SQL Programlama - Chapter 15İleri Seviye T-SQL Programlama - Chapter 15
İleri Seviye T-SQL Programlama - Chapter 15Cihan Özhan
 

Plus de Cihan Özhan (20)

MongoDB Overview
MongoDB OverviewMongoDB Overview
MongoDB Overview
 
MongoDB - NoSQL Overview
MongoDB - NoSQL OverviewMongoDB - NoSQL Overview
MongoDB - NoSQL Overview
 
MongoDB - JSON'a Genel Bakış
MongoDB - JSON'a Genel BakışMongoDB - JSON'a Genel Bakış
MongoDB - JSON'a Genel Bakış
 
AI and Machine Learning - Today’s Implementation Realities
AI and Machine Learning - Today’s Implementation RealitiesAI and Machine Learning - Today’s Implementation Realities
AI and Machine Learning - Today’s Implementation Realities
 
Mobil Uygulama Güvenliği (Mobile Security)
Mobil Uygulama Güvenliği (Mobile Security)Mobil Uygulama Güvenliği (Mobile Security)
Mobil Uygulama Güvenliği (Mobile Security)
 
Blockchain : Decentralized Application Development (Turkish)
Blockchain : Decentralized Application Development (Turkish)Blockchain : Decentralized Application Development (Turkish)
Blockchain : Decentralized Application Development (Turkish)
 
Golang Book - Genel Bakış
Golang Book - Genel BakışGolang Book - Genel Bakış
Golang Book - Genel Bakış
 
MLaaS - Presenting & Scaling Machine Learning Models as Microservices
MLaaS - Presenting & Scaling Machine Learning Models as MicroservicesMLaaS - Presenting & Scaling Machine Learning Models as Microservices
MLaaS - Presenting & Scaling Machine Learning Models as Microservices
 
Yapay Zeka Güvenliği : Machine Learning & Deep Learning & Computer Vision Sec...
Yapay Zeka Güvenliği : Machine Learning & Deep Learning & Computer Vision Sec...Yapay Zeka Güvenliği : Machine Learning & Deep Learning & Computer Vision Sec...
Yapay Zeka Güvenliği : Machine Learning & Deep Learning & Computer Vision Sec...
 
Endüstriyel Yapay Zeka ve Otonom Sistemler
Endüstriyel Yapay Zeka ve Otonom SistemlerEndüstriyel Yapay Zeka ve Otonom Sistemler
Endüstriyel Yapay Zeka ve Otonom Sistemler
 
AI Security : Machine Learning, Deep Learning and Computer Vision Security
AI Security : Machine Learning, Deep Learning and Computer Vision SecurityAI Security : Machine Learning, Deep Learning and Computer Vision Security
AI Security : Machine Learning, Deep Learning and Computer Vision Security
 
Yapay Zeka Güvenliği : Machine Learning & Deep Learning & Computer Vision Sec...
Yapay Zeka Güvenliği : Machine Learning & Deep Learning & Computer Vision Sec...Yapay Zeka Güvenliği : Machine Learning & Deep Learning & Computer Vision Sec...
Yapay Zeka Güvenliği : Machine Learning & Deep Learning & Computer Vision Sec...
 
Python Programlama Dili
Python Programlama DiliPython Programlama Dili
Python Programlama Dili
 
İleri Seviye T-SQL Programlama - Chapter 21
İleri Seviye T-SQL Programlama - Chapter 21İleri Seviye T-SQL Programlama - Chapter 21
İleri Seviye T-SQL Programlama - Chapter 21
 
İleri Seviye T-SQL Programlama - Chapter 20
İleri Seviye T-SQL Programlama - Chapter 20İleri Seviye T-SQL Programlama - Chapter 20
İleri Seviye T-SQL Programlama - Chapter 20
 
İleri Seviye T-SQL Programlama - Chapter 19
İleri Seviye T-SQL Programlama - Chapter 19İleri Seviye T-SQL Programlama - Chapter 19
İleri Seviye T-SQL Programlama - Chapter 19
 
İleri Seviye T-SQL Programlama - Chapter 18
İleri Seviye T-SQL Programlama - Chapter 18İleri Seviye T-SQL Programlama - Chapter 18
İleri Seviye T-SQL Programlama - Chapter 18
 
İleri Seviye T-SQL Programlama - Chapter 17
İleri Seviye T-SQL Programlama - Chapter 17İleri Seviye T-SQL Programlama - Chapter 17
İleri Seviye T-SQL Programlama - Chapter 17
 
İleri Seviye T-SQL Programlama - Chapter 16
İleri Seviye T-SQL Programlama - Chapter 16İleri Seviye T-SQL Programlama - Chapter 16
İleri Seviye T-SQL Programlama - Chapter 16
 
İleri Seviye T-SQL Programlama - Chapter 15
İleri Seviye T-SQL Programlama - Chapter 15İleri Seviye T-SQL Programlama - Chapter 15
İleri Seviye T-SQL Programlama - Chapter 15
 

Golang Book - Go Programlama Dili Temelleri

  • 1. Go Programlama Dili Temelleri Kitabın önceki bölümünde Go programlama diline genel bir bakış yaparak fikir sahibi olmaya çalışmıştık. Bu bölümde ise, Go programlama dilinin temel özelliklerine odaklanarak programlama dünyasına giriyoruz. Bu bölümde, her programlama dili için önemli olan temel programatik nesneler ve dil özelliklerini inceleyeceğiz. Akış Kontrol Programlama dillerinin en temel öğelerinden olan akış kontrol mekanizmaları, geliştirilen yazılımın kod çalıştırma akışını yönetebilmek için kullanılır. Go dilinde iki temel akış kontrol mekanizması vardır. Bunlar: - if - switch Diğer programlama dillerine göre Go dilindeki if ve switch deyimlerinin daha esnek ve efektif kullanılması nedeniyle, Go dilinde akış kontrolü yapmak hem kolay hem de daha yönetilebilir bir yapıya sahiptir. if En sık kullanacağımız akış kontrolü if deyimidir. Örnek: foo := 1 if foo == 1 { println("bar") } Yukarıdaki en basit halini uyguladığımız if kullanımını biraz inceleyelim. foo adında bir kısa değişken tanımlayarak bu değişkene bir(1) değerini atadık. Sonrasında if akış kontrolüne foo değişkenini vererek “Eğer bu değişkenin değeri 1 ise, if bloğuna gir” tanımını yapmış olduk! Bu örnek uygulamayı çalıştırdığımızda foo’nun değeri 1 olduğu için ekranda bar değerini gösterecektir. Not : foo ve bar değerlerinin bir anlamı yoktur. Bu değerler, yazılım dünyasında dummy data olarak kullanılır. if gibi akış kontrollerini kullanmanın temel amacı, true ya da false olarak geri dönüş yapan herhangi bir işlemin sonucuna göre işlem yapabilmektir. Yukarıdaki örnekte tek bir olasılığı programlayarak foo’nun değerine göre bir altındaki bloğa girişini kontrol ettik. Ancak bu yöntem gerçek uygulamalarda kullanılsa da, genelde yeterli olmaz. Bizim if akış kontrol üzerinde birden fazla işlemi kontrol ederek uygulamanın akışını değiştirebiliyor olmamız gerekiyor. Bu akış seçeneklerini çoğaltma işlemini Go dilinde else ve else if ile yapabiliyoruz. else bloğu : if bloğu şartı sağlanmazsa ve eğer else if bloğu kullanılmadıysa, else bloğu mutlaka çalışır. Örnek: age := 15 if age > 13 { fmt.Println("Yaşınız 13'den büyük olduğu için kayıt olabilirsiniz.") } else { cihanozhan.com
  • 2. fmt.Println("Sosyal platformlar senin için uygun değil!") } Örnek çıktısı: Yukarıdaki örnekte kullanılan yaş değerini 13 olarak değiştirerek tekrar deneyelim. Örnek çıktısı: Şimdi de, yukarıdaki örneğe else if bloğunu ekleyerek geliştirelim. Örnek: age := 13 if age > 13 { fmt.Println("Yaşınız 13'den büyük olduğu için kayıt olabilirsiniz.") } else if age < 13 { fmt.Println("Sosyal platformlar senin için uygun değil.") } else { fmt.Println("Sanırım senin yaşın tam sınırda! Bi düşünelim!") } Örnek çıktısı: Her programlama dilinin akış kontrollerine bakış açısı biraz farklılık gösterebilir. Go dili if akış kontrol mekanizmasına ek bir yeteneği daha dahil ederek if bloğunun başlık kısmında değişken tanımlamamıza izin veriyor. Böylelikle, sadece if bloğu içerisinde geçerli olacak değişkenler tanımlayabiliriz. if foo := 2; foo == 1 { println("bar") } else { println("buz") } Yukarıdaki örnekteki if bloğunda tanımlanan foo değişkeni sadece if bloğunda geçerlidir. Bu değişkene dışarıdan ulaşılamaz. Örnek çıktısı: buz Bu konuyla ilgili akıllara bir soru gelebilir. Eğer biz if bloğundan önce de foo adında bir değişken tanımlarsak, bu iki aynı isme sahip ama farklı olan değişkenler uygulamanın çalışmasını nasıl etkiler? Go dili, bu durumu bir hata olarak görmez ve derleme işlemini gerçekleştirir. Çünkü, if bloğundaki değişken ile dışarıda tanımlanan değişkenlerin çalıştığı etki alanları birbirinden farklıdır. Örnek: cihanozhan.com
  • 3. foo := 5 if foo := 2; foo == 1 { println("bar") } else { println("İç foo: " + " buz") println("İç foo: " + strconv.Itoa(foo)) } println("Dış foo: " + strconv.Itoa(foo)) Örnek çıktısı: if akış kontrol mekanizmasının daha kısa kod yazmak için oluşturulan yöntemini de kullanabiliriz. Örnek: func main() { if v, err := justDoIt(); err == nil { fmt.Println("value: ", v) } } func justDoIt() (string, error) { return "", fmt.Errorf("error") } Yukarıdaki yöntemde if akış kontrol mekanizmasında değer değişkeni olan v ile birlikte hata yönetimi için kullanacağımız err nesnesini de tanımlıyoruz. Sonrasında ise hata kontrolü yapacağımız işlemi gerçekleştirecek olan justDoIt() isimli fonksiyonu err değişkenine atıyoruz. Eğer bu fonksiyon herhangi bir hata mesajı dönerse if scope başlığında tanımladığımız err nesnesi nil olmayacaktır. Eğer herhangi bir hata ile karşılaşmazsak if içerisindeki kodlar çalıştırılarak uygulama doğal yaşam döngüsüne devam edecektir. En son uyguladığımız if örneğini birçok açık kaynak projede sık sık görebilirsiniz. Çünkü bu yöntem kod kısaltma amacıyla çok sık kullanılır. Ancak bazen de tam aksine kod okunabilirliğini azalttığı için bu yöntem tercih edilmeyebilir. switch Programatik olarak, genellikle switch deyimi if deyimiyle aynı işlemleri yapabilir. switch deyiminin en temel farkı, if deyiminden daha sade bir yapıya sahip olmasıdır. Bazı kaynaklarda bu akış kontrol mekanizmasına switch case denildiğini de görebilirsiniz. Bunun nedeni, switch ile birlikte kullanılması gereken case bloklarıdır. Örnek: foo := 2 switch { case foo == 1: println("bir") cihanozhan.com
  • 4. case foo == 2: println("iki") case foo > 3: println("Üç'ten büyük bir değer") } Örnek çıktısı: İki Yukarıdaki örnekte foo değişkenine 2 değerini atadık. Sonrasında ise her case bloğu ile bu değişkenin değerini kontrol ederek girilecek bloğu(yapılacak işlemi) belirledik. Not : Switch bloğundaki case alanlarıyla, if bloğundaki else if alanları aynı amaçla kullanılır. Şimdi de, switch ile biraz daha karmaşık bir işlem yaparak, öğrenci notuna göre sınav derecesini ölçelim. Ayrıca aşağıdaki örnekte switch içerisinde default alanları kullanmayı da inceleyeceğiz. switch içerisinde default bloğu ne işe yarar? default bloğunun amacı, if akış kontrolündeki else ile aynıdır. Eğer switch tanımındaki veri ile bloktaki case’lerden hiç biri eşleşmezse, uygulama default bloğuna girecektir. Örnek: var puan float64 fmt.Print("Son sınav puanınızı giriniz: ") fmt.Scanf("%v", &puan) switch { case puan <= 59: fmt.Println("Dereceniz F") case puan <= 69: fmt.Println("Dereceniz D") case puan <= 79: fmt.Println("Dereceniz C") case puan <= 89: fmt.Println("Dereceniz B") case puan <= 100: fmt.Println("Dereceniz A") default: fmt.Println("Lütfen 100'den küçük ya da eşit bir değer giriniz.") } Not : Go dosyanıza fmt paketini import etmeyi unutmayın! Örnek çıktısı: Uygulamaya 50 notunu girdik Dereceniz F Örnek çıktısı: Uygulamaya 101 notunu girdik Lütfen 100'den küçük ya da eşit bir değer giriniz. cihanozhan.com
  • 5. Konu Ödevi : Şu ana kadar if ve switch akış kontrollerinin kullanımını öğrendiniz. Ancak switch ile yaptığımız not uygulamasını if ile yapmamıştık! Uygulama ödevi olarak, bu not hesaplama uygulamasını if ile yapınız. Go dili, if akış kontrolünde olduğu gibi, switch akış kontrolünde de switch deyiminin başlık kısmında değişken tanımlayarak sadece switch içerisinde geçerli olmak üzere kullanılmasına izin veriyor. Örnek: switch foo := 1; foo { case 1: println("bir") case 2: println("iki") } İfadesiz switch kullanımı nedir ve nasıl kullanılır? İfadesiz switch kullanımı switch’in if akış kontrolü gibi karmaşık işlemlere cevap verebilmesini sağlayan bir switch genişletmesidir. number := 75 switch { case number >= 0 && number <= 50: fmt.Println("number değeri 0'dan büyük ve 50'den küçüktür") case number >= 51 && number <= 100: fmt.Println("number değeri 51'den büyük ve 100'den küçüktür") case number >= 101: fmt.Println("number değeri 100'den büyüktür") } Peki, switch içerisinde sadece sayısal değerleri mi kontrol edebiliyoruz? Hayır! Metinsel veri de kullanılabilir. Örnek: switch içerisinde çoklu ifade kullanımı page := "page2" switch page { case "index": fmt.Println("Ana sayfaya yönlendir.") case "about": fmt.Println("Hakkımda sayfasına yönlendir.") case "page1", "page2", "page3": fmt.Println("Bu sayfaları yayından kaldırdık!") // Page not found! default: fmt.Println("Bu görevi tanımlayamadık!") } Örnek çıktısı: Bu sayfaları yayından kaldırdık! Yukarıdaki örnekte görüldüğü üzere, bazen ihtiyaç duyacağımız metinsel verilerin switch ile kullanımı da Go dilinde mümkündür. cihanozhan.com
  • 6. Son olarak, switch ile gerçek dünya uygulamalarında kullanabileceğimiz örneklerden birini daha yapalım. Go dilinin işletim sistemleriyle ilgili açıklamalar yaparken, Go uygulamasının üzerinde çalıştığı işletim sistemi ve platformu tanıyabildiği ve buna göre işlemler yapabildiğinden bahsetmiştik. Bu işlemi basit bir şekilde örnekleyelim. Örnek: import ( "fmt" "runtime" ) func main() { fmt.Print("Go runs on ") switch os := runtime.GOOS; os { case "darwin": fmt.Println("OS X.") case "linux": fmt.Println("Linux.") default: // freebsd, openbsd, // plan9, windows... fmt.Printf("%s.", os) } } Örnek çıktısı: Go runs on windows. Yukarıdaki uygulamanın amacı çok nettir. Go’nun üzerinde çalıştığı işletim sistemini bulmak ve bu işletim sistemine özgü metodu çalıştırmaktır. Ben Windows işletim sistemi üzerinde çalıştığım için de uygulamanın çıktısı yukarıdaki gibi oldu. Bu örnek Go dili tur sayfalarında da kullanılan temel bir örnektir. İlgili sayfayı ziyaret etmek için: https://tour.golang.org/flowcontrol/9 Fallthrough … cihanozhan.com
  • 7. Diziler Geliştirilen tüm yazılımların bazı genel gereksinimleri vardır. Bunlardan birisi de, uygulama aktif olarak çalışırken bilgisayar hafızasında yer tutmaktır. Bunu en temel olarak değişkenler ile gerçekleştiriyoruz. Ancak bazı durumlarda bu yeterli olmaz. Bazen uygulama içerisinde aynı ya da farklı veri tiplerine sahip birden fazla(bazen binlerce) veriyi bir bütün olarak tutmak gerekebilir. Örneğin, switch akış kontrol örneğinde geliştirdiğimiz öğrenci not uygulamasını ele alalım. Bu uygulamadaki öğrenci notlarının tamamını tek bir nesne içerisinde tutmak isteyebiliriz. Ya da veritabanından elde ettiğimiz kullanıcılar listesini, uygulama çalışırken hafızada tutmak, uygulama performansı açısından faydalı olacaktır. İşte bu ve daha birçok nedenden dolayı ihtiyacımız olan bir programlama nesnesi var: Diziler Diziler için, en basit tabirle değişkenler listesi demek yanlış olmaz. Diziler hakkında detaylı açıklamalara girmeden önce, kuralları daha iyi benimseyebilmeniz için küçük bir dizi örneği yapacağız. Dizi İlklendirmek(Array Initialization) Bir dizi nesnesine değer ataması yapabilmek ya da veri tutmasını sağlayabilmek için öncelikle ilklendirmek(initialization) yapılmalıdır. Bu işlem, bir dizinin bilgisayar hafızasında eleman sayısı ve veri tipinin kapasitesi kadar kullanım alanına sahip olmasını sağlar. En basit tabirle, ilklendirilmemiş bir dizi ham bir nesnedir diyebiliriz. Bu nesneyi kullanıma hazır hale getirmek için de ilklendirme işlemini yaparız. Örnek: scores := [3]int{} Yukarıdaki örnekte, en basit haliyle bir dizi değişkeni tanımladık. Bu dizi değişkeninin adını scores olarak belirledik ve veri tipi olarak integer, tutacağı eleman sayısının da 3 olacağını bildirdik. Artık bu dizi değişkenini kullanarak veri ekleyebilir, veriyi elde edebilir ya da değiştirebiliriz. Şimdi Go dilindeki diğer dizi tanımlama yöntemlerine bir göz atalım. Otomatik Boyutlandırma İle Dizi Oluşturmak Bir dizinin eleman sayısı sonradan değiştirilemez. Ancak dizinin oluşturulma aşamasında(ilklendirme) diziye dinamik değerler vererek bu diziyi dinamik şekilde oluşturabiliriz. Örnek: numbers := [...]int{56, 65, 100} Bu kullanım yönteminin kafaları karıştırmaması için, şöyle bir açıklama getirebiliriz: Bu kullanımda, Go derleyicisinin davranışı çıkarım yapma üzerine kuruludur. Yani, biz numbers dizisini oluştururken, bu diziye eklemek istediğimiz veriyi de birlikte gönderiyoruz. Go derleyicisi bu aşamada, bizim gönderdiğimiz elemanların sayısını toplayarak, geri planda bu eleman adedine göre bir dizi değişkeni oluşturur. Bu da, bizim ilklendirme aşamasında dinamik eleman sayısına sahip bir değişken oluşturabilmemizi sağlamaktadır. Short hand Dizi Oluşturmak Short hand yöntemi söz dizimi olarak ‘Otomatik Boyutlandırma’ yöntemine çok benzese de aynı değildir. Bu yöntemde amaç, dizi değişken değerinin dinamik olarak belirlenmesi değil, sadece dizinin ilklendirme sırasında veriyi de birlikte göndermektir. cihanozhan.com
  • 8. Örnek: numbers := [3]int{43, 88, 70} Yukarıdaki tanımlamada görüldüğü üzere, integer tipine eleman sayısını veren köşeli parantez içerisinde eleman sayısını belirtiyoruz. Dizi tanımının devamında ise, 3 eleman için değer ataması yapıyoruz. numbers dizi değişkenini aşağıdaki gibi de tanımlayabilirdik: Örnek: numbers := [3]int{43} Bu tanımlama yönteminde de eleman sayısı değişmez ve gene 3 elemanlı bir dizi değişkeni oluşturduk. Ancak diğer kullanımdan tek farkı, bu değişkende sadece tek bir değer ataması yaptık. Ve eğer bu kullanımı uygulayarak dizi değişkenini ekrana yazdırırsak aşağıdaki gibi bir sonuç elde ederiz. Örnek çıktısı: [43 0 0] Görüldüğü üzere, artık 3 elemanlı bir dizi değişkenine sahibiz. Ancak içerisinde sadece tek bir eleman değeri var. Diğer iki adet sıfır(0) ise, dizinin ilklendirilmesi sırasında Go derleyicisi tarafından atanan başlangıç değerleridir. Diziler Hakkında Bilinmesi Gereken Temel Unsurlar Yukarıda oluşturduğumuz diziyi kullanmak için bilmemiz gereken birkaç ön bilgi daha var. - Diziler tanımlama sırasında belirtilen eleman sayısı kadar eleman alabilir. Bilgisayar bilimlerinde dizi kavramının temel kurallarından biri, dizilerin eleman sayısı adedince eleman alabileceğidir. Ayrıca, bir dizinin eleman sayı sınırı, dizinin ilklendirme işlemi sırasında belirtilmelidir. Bir diziden bir eleman silinse bile, o elemanın hafızadaki yeri, dizi işaretçisi tarafından bilinir ve kullanılmaya devam edilir. Silinen elemanın yerine yeni bir değer yazılabilir. - Dizilerin eleman sayısı sonradan değiştirilemez! Dizilerin eleman sayısı sonradan değiştirilemez! Programlama dilleri, mevcut bir dizinin eleman sayı sınırını değiştirebilmek için farklı yöntemler uygulasalar da, bu işlem sadece mevcuttaki değiştirilemezlik sorununu programcıya yansıtmamak için uygulanan bir çözüm yöntemidir. Mevcut bir dizinin eleman sayı kapasitesini değiştirdiğinizde, aslında o programlama dili o diziyi geri planda yok eder ve yeni bir dizi oluşturarak önceki dizinin elemanlarını yeni diziye aktararak kullanmanıza izin verir. Buna genel olarak yeniden boyutlandırma(resize) işlemi denir ve bu yeterli bir çözümdür. - Dizilerin elemanlarına index’ler üzerinden erişilir. Dizilerin elemanlarına elemanların sırası ile değil, elemanların index’leri üzerinden erişilir. Bu kural programlamaya yeni başlayanların en sık karıştırdıkları konulardan biridir. Dizi elemanlarının sayısı sayma sayılarıyla(1 … ~) başlar. Ancak, dizi index’leri ise doğal sayılar(0 … ~) ile başlar. Bu nedenle, eğer dizinin ilk elemanına ulaşmak isterseniz 1 değil, 0 değerini kullanmalısınız. cihanozhan.com
  • 9. Dizi Kullanımı Şimdi daha önce oluşturduğumuz scores adındaki diziyi kullanalım. Örnek: scores := [3]int{} // Diziyi ilklendirmiştik! scores[0] = 34 // Diziye değer ataması yapmak! scores[1] = 87 scores[2] = 91 fmt.Println(scores) // Diziyi ekrana basalım. Örnek çıktısı: [34 87 91] Bu örnek üzerinden bir dizinin tek bir elemanını elde etmeyi de inceleyebiliriz: Örnek: fmt.Println(scores[1]) // Dizinin 1. index’ini almak(2. Eleman) Örnek çıktısı: 87 Yukarıdaki örnekte, basit bir integer dizi tanımlayarak scores adındaki dizimize integer veri tutacağını bildirdik. Ayrıyeten, bu dizinin 3 elemana sahip olacağını ve buna göre bir hazırlık yapmasını da Go derleyicisine iletmiş olduk! Bu bildirim sayesinde, Go derleyicisi bu dizi için hafızada 3 integer kapasiteli hafıza alanı oluşturacak ve bu hafıza alanlarının adresini scores isimli dizinin işaretçisi(pointer) olarak tanımlayacaktır. Bu sayede, biz scores üzerinden bu elemanların hafızadaki alanlarına erişebileceğiz. Başka bir gerçek dünya örneği daha yapalım. Örneğin, herhangi bir veri kaynağından elde ettiğimiz renk isimlerini bir listede tutmak akıllıca olabilir. Bu renk listesini uygulama ayakta kaldığı sürece kullanabiliriz. Bu örnekte, elimizde sadece 3 renk(eleman) olacak. var colors [3]string colors[0] = "Red" colors[1] = "Green" colors[2] = "Blue" fmt.Println(colors) Bir Dizinin Eleman Sayısını Bulmak Go ile yazılım geliştirirken birçok kez eleman sayısını elde etmemiz gerekecek. Bu işlem, Go diliyle birlikte gelen built-in fonksiyonlarla birlikte çok kolaydır. Dizi elemanlarının toplamını bulmak için len(arrayName) fonksiyonunu kullanacağız. Örnek: // 1. Dizi var colors [3]string cihanozhan.com
  • 10. colors[0] = "Red" colors[1] = "Green" colors[2] = "Blue" // 2. Dizi var numbers = [5]int{5, 3, 1, 2, 4} // Dizilerin eleman sayılarının toplamını hesaplayıp ekrana basalım fmt.Println("Renklerin toplam adedi:", len(colors)) fmt.Println("Rakamların toplam adedi:", len(numbers)) Örnek çıktısı: Renklerin toplam adedi: 3 Rakamların toplam adedi: 5 Döngü İle Dizinin Değerini Elde Etmek Şu ana kadar farklı birçok dizi tanımlaması yaptık. Bu tanımlamalar sadece diziler konusunu hızlı kavrayabilmek için verilen temel seviye örneklerdi. İlerleyen bölümlerde bu nesneleri farklı birçok uygulama içerisinde kullanacağız. Şimdi bir dizinin içerisindeki veriyi nasıl döngü oluşturarak ekrana yazdıracağımıza bakalım. Not : Bir sonraki bölümde döngüleri detaylı bir şekilde inceleyeceğiz. Ancak bu bölümde temel seviyede döngü ile dizi kullanımını örneklememiz dizileri daha iyi kavramanıza yardımcı olacaktır. Örnek: strPattern := "Bu değerin x'deki index sırası %d ve değeri %.2fn" x := [...]float64{65.4, 334.7, 3.21, 97} for i := 0; i < len(x); i++ { fmt.Printf(strPattern, i, x[i]) } Örnek çıktısı: Döngü ile dizi kullanımı örneğinde, ilk olarak ekranda göstereceğimiz metni programatik format(yer tutucular) ile birlikte hazırladık. Bu string formatı içerisindeki %d yer tutucu desenini integer gibi sayısal değerleri, %.2f yer tutucu desenini ise ondalıklı verileri ekrana basmak için kullanıyoruz. Sonrasında x adında, veri tipi float64 olan, içerisinde 4 adet veri olan bir dizi değişkeni oluşturduk. Bundan sonraki satırda ise, döngü işlemine geçtik. Döngüde dikkat ederseniz i := 0 gibi bir alan mevcut. Bu alanda dizi içerisindeki index’lere eş gelecek değeri üretecek değişkeni oluşturduk. Ve dikkat ederseniz, bu alanın değeri 0’dan başlamaktadır. Çünkü, hatırlarsanız dizilerde index değerleri sıfır(0)’dan başlıyordu. Sonrasında ise, len() fonksiyonunu kullanarak x dizisinin eleman uzunluğunu elde ettik. Ve bu sayede, sıfır(0) index’inden, dizinin eleman sayısına kadar olacak şekilde bir döngü başladı. cihanozhan.com
  • 11. Diziler Referans Tipi Midir? Değer Tipi Mi? Bu bölümde, bu kitabın ilk bölümünde incelediğimiz referans ve değer tipi kavramının dizilerdeki yansımasını inceleyeceğiz. Kısa hatırlatma: - Referans tipindeki nesneler verinin hafızadaki adresini tutarlar ve kopyalanırken de hafıza adresini kopyalarlar. Verinin kendisini değil! - Değer tipindeki nesneler verinin kendisini tutar ve kopyalanması halinde verinin kendisini kopyalar Peki diziler referans tipine mi dahiller, yoksa değer tipine mi? Örnek: co := [...]string{"Turkey", "USA", "China", "India", "Germany"} x := co // co nesnesini x adında yeni oluşturulan bir diziye atadık! x[0] = "Pakistan" fmt.Println("co değeri: ", co) fmt.Println("x değeri: ", x) Örnek çıktısı: Yukarıdaki örnek çıktıyı yorumlayalım: co adında yeni bir dizi değişkeni oluşturarak, bu değişkene 5 adet ülke adını veri olarak ekledik. Sonraki satırda x adında yeni bir değişken oluşturduk. Bu oluşturduğumuz x değişkenine de co adındaki dizi değişkeni atadık! Bunun anlamı, ‘co dizisindeki değerleri x’e kopyala’ demektir. Buraya kadar her şey olağan! Sonraki satırda ise x değişkeninin sıfırıncı(0) index’indeki Turkey değerini değiştirmek istedik. Eğer diziler bir referans tipi ise bu değer ataması x dizisinin işaretçisi üzerinden co değişkeninin de verisini değiştirecektir. Ancak sonuç çıktısından görüldüğü üzere, x dizisi üzerinde yapılan bir değişiklik sadece x’i etkilemektedir. Bu değişiklik co dizisini etkilememektedir. Bu sonuç da bize dizilerin bir değer tipi olduğunu ispatlamaktadır. Çok Boyutlu Diziler Çok boyutlu diziler, her bir item’ında bir dizi bulunduran dizilerdir. Normal dizilerin her item’ında sadece tek bir eleman, yani değer vardır. Ancak çok boyutlu diziler, her item’ında birer dizi taşırlar. Bu nedenle, çok boyutlu bir diziden elde edilen her item’ın da alt elemanları elde edilebilir. Not : Bu konu çok karmaşık gibi görünebilir. Ancak çok boyutlu bir dizinin temel prensipleri çok açıktır. Bu prensipleri anladığınız takdirde tüm çok boyutlu dizi yapılarını rahatlıkla anlayabilir ve oluşturabilirsiniz. Basit bir çok boyutlu dizi oluşturalım. Bu dizi 3’e 2’lik bir yapıya sahip olsun. Örnek: var unicorn [3][2]string Yukarıdaki çok boyutlu diziyi string veri tipinde oluşturduk. Diziyi oluştururken belirttiğimiz 3 ve 2’lik sayılar ise dizinin temel yapısını tanımlıyor. Buradaki 3 sayısı ana dizinin kaç eleman alacağını belirtir. Bu 3 dizi cihanozhan.com
  • 12. elemanının her bir item’ı ise birer dizi alacaktır. Ve aynı zamanda bu 3 dizi item’ın her birinin kapasitesi de 2 string eleman alacak şekilde oluşturulmuştur. Şimdi bu oluşturduğumuz unicorn isimli çok boyutlu değişkene veri ekleyelim. unicorn[0][0] = "Apple" unicorn[0][1] = "Google" unicorn[1][0] = "Microsoft" unicorn[1][1] = "Uber" unicorn[2][0] = "Facebook" unicorn[2][1] = "Oracle" Veri ekleme kodlarına dikkat ederseniz, soldaki index’ler 0’dan başlayarak 2 dahil 2’ye kadar gidiyor. Bunun anlamı, 3 elemanlı bir dış diziye sahibiz. Sağdaki index alanlarında ise, sadece 0 ve 1’ler mevcut! Bunun anlamı ise, sadece 2 adet eleman alabilen bir iç diziye de sahibiz. Bu örnekteki her dış dizi, 2 eleman alabilen bir iç diziye sahiptir. Bu çok boyutlu dizi içerisinden istediğimiz bir veriye nasıl ulaşabiliriz? Eğer sadece tek bir veriyi bulmayı hedefliyorsak ve yukarıdaki gibi bir dizilime sahipsek, aşağıdaki gibi yapabiliriz. Örneğin, Uber verisini elde etmek istiyorsak: Örnek: fmt.Println(unicorn[1][1]) Örnek çıktısı: Uber Aynı şekilde bu yöntem ile veri değişikliği de yapabiliriz. Örnek: unicorn[1][1] = "Yahoo" fmt.Println(unicorn[1][1]) Örnek çıktısı: Yahoo Çok boyutlu dizilerin bir başka oluşturulma yöntemi ise aşağıdaki gibidir: Örnek: // Diğer bir çok boyutlu dizi oluşturma yöntemi data := [3][2]string{ {"apple", "pear"}, {"banana", "cucumber"}, {"lemon", "watermelon"}, } Not : Döngüler konusu ve range kullanımı bir sonraki bölüm olan Döngüler bölümünde detaylı bir şekilde cihanozhan.com
  • 13. anlatılmaktadır. Ancak döngülerin diziler ve dizilerden veri elde etmede aktif olarak kullanılması nedeniyle bu bölümde de bir örnekle incelenmiştir. Bir sonraki bölümde döngü yapılarını inceledikten sonra tekrar bu örneğe göz atmanızı öneririm. // Çok boyutlu dizinin her bir item'ını iç içe döngü ile ekrana basmak // loop1 döngüsü, yukarıda tanımlanan data üzerinde dış dizi için döner // loop1 her item’ında loop2’nin bir iç diziye sahip olmasını sağlar for _, loop1 := range data { // loop2 döngüsü, loop1 üzerinde bir iç dizi almak için döner for _, loop2 := range loop1 { fmt.Printf("%s ", loop2) } fmt.Printf("n") } Örnek çıktısı: apple pear banana cucumber lemon watermelon Döngüler Programlama dünyasında, tekrar eden bazı işlemleri yapmak gerekebilir. Bu bazen bir veritabanından elde edilen veri üzerinde, bazen de network üzerinden elde edilen veri paketleri üzerinde işlem yapmak olabilir. Bu tür işlemleri yapabilmek için, belirli kurallara göre işlemleri tekrar edebilme yeteneği gerekir. Programlama dünyasında bu amaçla çalışan nesnelere döngüler diyoruz. Bu bölümde, Go dilinin döngü yeteneklerini inceleyeceğiz. Go programlama dilinde diğer diğer dillerin aksine tek bir döngü yapısı vardır: for for Diziler konusunu incelerken for döngüsünü dizi örnekleri üzerinde kullanmıştık. Şimdi bu bölümde for döngüsünü detaylı şekilde inceleyeceğiz. for söz dizimi: for başlatma; şart; işlem { } İlk basit for örneğimizi oluşturalım ve inceleyelim. Elimizde basit bir ekrana yazma işlemi var ve bunu N defa yapacağız. Örnek: for i := 0; i < 5; i++ { fmt.Println("i'nin değeri:", i) } Örnek çıktısı: cihanozhan.com
  • 14. i'nin değeri: 0 i'nin değeri: 1 i'nin değeri: 2 i'nin değeri: 3 i'nin değeri: 4 Not : Bu for döngü yöntemi C-family dillerin tümünde geçerli bir kullanımdır. Go dili de C dilinin bir çok iyi yönünü bünyesine dahil ettiği için, bu kullanımı olduğu gibi desteklemektedir. Yukarıdaki örnekte, ekrana yazma işlemini 5 kez tekrarlamayı sağlayan bir kod yazdık. Şimdi bu kullanımı adım adım inceleyelim. - başlatma: Bu alanda bir değişken tanımlayarak for döngü bloğunun bu değişkenin değeri ile kontrol edilebilmesi sağlanır. Bu değişken genel olarak sıfır(0)’dan başlatılır ve döngü her çalıştığında, istenen algoritmaya göre değişmekle birlikte, azaltılır ya da artırılır. Bu sayede döngünün belirtilen işlemi kaç kez yaptığını bilebiliriz. Bu değişken sadece for döngü bloğunun içerisinde geçerlidir. Bu değişkene dışarıdan erişilemez. - şart: başlatma bloğunda tanımlanan değişkenin değeri için bir şart belirtmemizi sağlar. Örneğin, i < 5 olduğu sürece devam et gibi bir şart verebiliriz. - işlem: bu scope ise döngünün yönünü belirler. Başlatma bloğunda tanımlanan değişkenin ileri ya da geri olacak şekilde, artırılması ya da azaltılmasını sağlayarak uygulama sürecinde belirleyici rol oynar. Eğer for döngüsünün şart alanını boş bırakırsak ne olur? Eğer for döngüsünün şart alanını boş bırakırsak, döngünün bir bitiş değeri(limiti) olmayacaktır. Bu da doğal olarak bir sonsuz döngü tanımladığımız anlamına gelir. Not : Aşağıdaki kodu çalıştırdıktan sonra sonsuz döngü oluşacaktır. Visual Studio Code editöründe sonsuz döngüyü kırmak için terminal üzerindeyken CTRL+C klavye kombinasyonunu kullanmanız yeterlidir. Örnek: for i := 0; ; i++ { fmt.Println("i'nin değeri: ", i) } Örnek çıktısı … i'nin değeri: 2837 i'nin değeri: 2838 i'nin değeri: 2839 … Eğer döngünün işlem alanını boş bırakırsak ne olur? Eğer döngünün işlem alanını boş bırakırsak, döngü gene sonsuz döngü olacaktır. Ancak döngünün yönünü belirtmediğimiz için i değişkeninin değeri artmayacak ve ekrana sürekli sıfır(0) değeri yazılacaktır. Bu kullanım çok özel durumlar haricinde kullanılan bir yöntem değildir. Ancak for döngüsünün davranışlarını anlayabilmeniz için önemlidir. Örnek: for i := 0; i < 3; { cihanozhan.com
  • 15. fmt.Println("i'nin değeri: ", i) } Örnek çıktısı: … i'nin değeri: 0 i'nin değeri: 0 i'nin değeri: 0 … for ile While Döngü Yöntemi Oluşturmak Normal bir for kullanımında oluşturduğumuz başlatma değişkeni sadece for scope’u içerisinde geçerli olduğu için bu değişkene dışarıdan erişemeyiz. Ancak bazen döngü içerisinde üretilen ve değeri değişen veriye döngü dışından erişme ihtiyacımız olabilir. Şimdi bu durumu nasıl yönetebileceğimize bakalım. Örnek: x := 1 for x <= 10 { fmt.Println("x değeri: ", x) x += 1 } Yukarıdaki örnekte, for scope’u dışında x adında bir değişken tanımladık ve bu değişkenin for scope’u içerisinde kullanılmasını sağladık. Bu sayede, döngünün içerisinde üretilen yeni değerlere döngünün dışından da erişebildik. Ayrıca, dikkat ederseniz normalde işlem scope’unda yaptığımız değer artırma işlemini de for döngüsünün içerisinde yaptık. Örnek sonucu: range Önceki bölümlerde diziler üzerine birçok işlem gerçekleştirdik. Dizileri hatırlarsanız, döngü ile dizilerin her bir item’ını elde ederek, bu item’lar üzerinde çeşitli işlemler yapabiliyorduk. Ancak modern yazılım geliştirme süreçlerinde, bir integer’dan daha karmaşık veri tiplerine sahip dizi nesneleri üzerinde çalışmamız gerekmektedir. Bu tür karmaşık diziler üzerinde iteration(tekrarlama) uygulayabilmek için Go diline eklenen for döngü yapısına da range diyoruz. Not : C# programlama diliyle ilgilenenler için; Go dilindeki for range uygulaması(implementation), C# dilindeki foreach döngü yapısının Go dilindeki karşılığıdır. cihanozhan.com
  • 16. Söz dizimi: for key, value := range arrayObject { println(key, value) } Şimdi for range ile ilgili basit bir örnek yapalım. Örnek: nums := []int{5, 6, 7} sum := 0 for _, num := range nums { sum += num } fmt.Println("toplam: ", sum) Örnek çıktısı: toplam: 18 Yukarıdaki for range döngüsünde nums dizisi üzerinde bir tekrarlama işlemi yaptık. Yalnız dikkat ederseniz, for tanımından sonraki “_, num” kısmında bir alt çizgi kullandık. Bunun nedeni, for range yapısının bize iki değer veriyor olmasıdır. Bu değerlerden ilki elemanın index’i, diğeri ise elemanın değeridir. Ancak biz bu uygulamada elemanın index’ini almak istemediğimiz için, index alanına bir değişken adı vermek yerine, alt çizgi( _ ) kullandık. Eğer bu index değerine de ihtiyacımız var ise, şu şekilde bu değeri elde edebiliriz. Not : Kitabın ilk bölümlerinden hatırlarsanız, Go dili tanımlanmış ama kullanılmamış nesnelerin kod içerisinde bulunmasına izin vermiyor ve derleme zamanında hata fırlatıyor. Bu nedenle, döngünün index alanında bir değişken tanımlarsanız, onu kullanmak zorunda kalırsınız. Aksi halde, alt çizgi ile bu sorunu çözebiliyoruz. Örnek: nums := []int{5, 6, 7} sum := 0 for ind, num := range nums { sum += num fmt.Println("index: ", ind) } fmt.Println("toplam: ", sum) Örnek çıktısı: index: 0 index: 1 index: 2 toplam: 18 Go dilinde for range döngü modelini birçok farklı nesne(map, slice, struct vb.) üzerinde kullanabiliyoruz. Bu nesnelerin bir kısmını henüz incelemediğimiz için, bu örneklerle ilgili uygulamaları sonraki bölümlere bırakıyoruz. cihanozhan.com
  • 17. Bir for döngüsündeki range yapısını farklı bir şekilde de kullanabiliriz. Örneğin, elimizde bir liste var ama verinin kendisini elde etmeden sadece veri adedince bir işlemin gerçekleştirilmesini istiyorsak aşağıdaki yöntemle veriyi göz ardı ederek veri adedince dönen bir döngü oluşturabiliriz. list := map[string]string{ "X": "Ferrari", "Y": "Jaguar", } for range list { fmt.Println("Dönüyor") } Örnek çıktısı: Dönüyor Dönüyor Son uyguladığımız döngü yapısı biraz anlamsız gibi görünebilir. Ancak bu yöntemi Go dilindeki channel nesneleriyle birlikte kullanılabiliyoruz. break ve continue Döngüler gerekli şartlar sağlanana kadar dönmek üzere tasarlanan nesnelerdir. Ancak bazen bir döngünün iç akışını kontrol etmemiz ve değiştirmemiz gerekebilir. - break: Matematiksel bir değeri bulana kadar işleme devam eden bir döngüye sahip olduğumuzu varsayalım. Eğer bu döngüyü sonlandırmazsak, bu işlem bitene kadar devam etmesi gerekir. Peki matematiksel sonucu elde edersek, döngüyü nasıl kıracağız? İşte bunu sağlayan komutun adı break’tir. - continue: break için verdiğimiz matematiksel hesaplama örneğinin aynısı continue komutu için de geçerli olsun. Bu işlem devam ederken 10 adımlı bir algoritma çalıştırdığımızı varsayalım. İlk 3 matematiksel işlemin sonucunu biliyoruz. Eğer bu ilk 3 matematik işleminin sonucu hatalı ise, sonraki 7 matematiksel işlemin bir önemi kalmayacaktır. Daha sonra, bu ilk 3 işlemden sonraki 7 işlemi yapmasını beklemek mantıklı mıdır? Bu durumda, döngüyü kırmadan sadece bu işlemden vazgeçip döngünün başına dönülmesi, zaman ve kaynak yönetimi açısından daha mantıklıdır. İşte bu döngüyü kırmadan döngünün başına dönmemizi sağlayan komutun adı continue’dur. Bu iki komutu da tek bir uygulama içerisinde örnekleyerek nasıl çalıştığını inceleyeceğiz. Örnek: import ( "bufio" "fmt" "os" "strconv" "strings" ) func main() { reader := bufio.NewReader(os.Stdin) i := 0 cihanozhan.com
  • 18. for { fmt.Print("Enter value: ") str, _ := reader.ReadString('n') val, err := strconv.Atoi(strings.TrimSpace(str)) if err != nil { fmt.Println("Beklenmeyen bir değer girildi. Başa dönülüyor.") continue } if val == 3 { fmt.Println("Döngü kırıldı!") break } if val == 5 { fmt.Println("Şartlar sağlanamadı. Döngünün başına dönüldü.") continue } fmt.Println("index'in değeri: ", i) i++ } fmt.Println("Uygulamanın sonu.") } Örnek çıktısı: Bu örneği çalıştırdığımızda, bizden nümerik bir değer girmemizi isteyecektir. Bu alan için eğer 3 değerini girersek, döngü sonlanarak ekranda “Döngü kırıldı! Uygulamanın sonu." mesajını görürsünüz. Ancak eğer uygulamaya 5 değerini girerseniz, uygulama bulunduğu konumdan başa dönerek akışı tekrar başlatır. Bu işlem döngünün yeniden başladığı anlamına gelmez, sadece bir sonraki döngü sürecine geçilerek devam edilir. Break/Continue - 1 Break/Continue - 2 cihanozhan.com
  • 19. Ayrıca, yukarıdaki uygulamada küçük bir hata yönetimi işlemi de gerçekleştirdik. Bunun nedeni, gerçek bir uygulama içerisindeki olası hata durumlarını örneklemek ve bu durumda neler yapılabileceğini anlamanızı sağlamaktır. Örneğin, bu uygulamada kullanıcıdan bir sayısal değer istiyoruz. Ancak bu değeri öncelikle metinsel veri(string) olarak alıyoruz. Ondan sonra da, geri planda bu metinsel veriyi sayıya çeviriyoruz. Eğer kullanıcı veri girişi aşamasında gerçek bir sayı girmezse, bu uygulama çökecektir! İşte bu olası durumu yönetebilmek için, veri dönüşümü gerçekleştirdiğimiz kısımdaki err hata nesnesini aktif ederek kullandık. Ve eğer err nesnesi nil(null) değilse, bu işlem bir hata üretmiş demektir. Eğer uygulamada bir hata meydana gelirse, uygulamanın continue ile başa dönerek devam etmesini sağladık. Sonsuz Döngü Programlamada bazı işlemlerin sürekli olarak yapılması gerekebilir. Örneğin, eğer bir bilgisayar ağından veri okuma işlemi yapıyorsanız, bunu genellikle sürekli ve anlık olarak yapmalısınız. Bu işlemi yapabilmek için de, ağ üzerindeki bir port’u anlık olarak dinleyen bir yazılım geliştirmelisiniz. Bu ve daha birçok kullanım amacı için sonsuz döngüler oluşturulabilir. Söz dizimi: for { } Sonsuz döngü söz dizimi için basit bir örnek yapalım. Örnek: for { fmt.Println("Merhaba Mars!") } Örnek çıktısı: Bu işlemin sonucunda ekrana sürekli olarak “Merhaba Mars!” metni basılacaktır. cihanozhan.com
  • 20. Slice Slice, Go programlama diline özgü, yeni bir programlama nesnesidir. Bir slice, arka planda dizileri kullanan ve dizinin hafızadaki adresini işaret eden yeni bir dizi kullanım yöntemidir. Bir slice’ın kendisine ait veri tutma yeteneği yoktur. Mevcut bir dizi üzerinden bir slice oluşturulabildiği gibi, bir slice’ı doğrudan da oluşturabiliriz. Ancak doğrudan bir slice oluştursak bile, Go derleyicisi arka planda bu slice için bir dizi tanımlaması yapar ve oluşturulan slice’ın işaretçisini bu dizinin hafıza adresine bağlar. Not : Slice nesnesinin Türkçe karşılığı “dilim” olarak tanımlanır. Bir slice oluşturmanın yöntemleri: - Bir dizi üzerinden slice oluşturmak - Bir diziden bağımsız olarak yeni bir slice oluşturmak İlk olarak bir dizi üzerinde nasıl slice oluşturabileceğimizi inceleyelim. Bir dizi üzerinde birden fazla slice oluşturulabilir. Bu oluşturulan slice’ların tümü tek bir dizinin hafızadaki adresine bağlı olurlar. Eğer bir dizi üzerinde oluşturulan slice’lardan herhangi birisi üzerindeki elemanlarda bir değişiklik yapılırsa, bu işlem doğrudan işaret edilen dizinin gerçek verisi üzerinde gerçekleştirilir. Bu nedenle, herhangi bir slice’ta yapılan değişiklik, hem ana dizinin verisini, hem de bu dizi üzerinden üretilen tüm slice’ları etkiler. Örnek: // Bir dizi tanımlıyoruz numsArr := [5]float32{3.23, 4.56, 1.74, 76.94, 13.53} Bir dizi ya da slice üzerinde, yeni bir slice oluşturmak için kullandığımız veriyi kesme yöntemi aşağıdaki gibidir: array|slice[baslangic:bitis] Şimdi bu dizi üzerinde yeni bir slice oluşturalım. slice1 := numsArr[:] slice1 isimli slice’ımız numsArr dizisinin tüm verisini yansıtacak şekilde ayarlandı. Bunu sağlayan şey ise [:] tanımıdır. Bu işlemin aynısını numsArr[0:] yöntemiyle de elde edebilirsiniz. Oluşturulan slice verisini ekrana bastırmak için: fmt.Println(sliceName) Yukarıdaki söz diziminde bulunan start alanı, veri kesme işleminin hangi index’ten başlayacağın, end alanı ise bu kesme işleminin hangi index’e kadar olan veriyi kapsayacağını belirtmek için kullanılır. slice1 isimli slice’ı oluştururken start ve end alanlarını boş bıraktık. Bunun anlamı, herhangi bir limit olmadan tüm veriyi yeni slice’a istiyoruz demektir. numsArr dizisindeki 4.56 ondalıklı değerinin indexi bir(1)’dir. Sadece bu veriyi alacak bir slice oluşturmak istersek şu şekilde yapabiliriz. slice2 := numsArr[1:2] // sonuç: [4.56] cihanozhan.com
  • 21. Not : Dizilerdeki index’leme mantığını iyi bilen bir geliştirici için slice’lar üzerinde çalışmak çok kolaydır. Diğer bir örnek olarak, dizi elemanlarının ilki hariç, geri kalan tüm elemanları alarak yeni bir slice oluşturalım. slice3 := numsArr[1:] Veri kesme alanında dinamik bir belirteç de kullanabiliriz. Örneğin, numsArr dizisinin toplam eleman uzunluğunun 2 eksiği kadar bir elemanı elde edelim. Örnek: slice4 := numsArr[:len(numsArr)-2] Örnek çıktısı: [3.23 4.56 1.74] Not : Yukarıdaki örnekte kullandığımız len(arrayName) fonksiyonu ile bir dizi ya da slice’ın elemanlarının toplamını elde edebiliyoruz. Uygulama Ödevi : Yukarıdaki gibi bir dinamik veri kesme yöntemini cap() fonksiyonuyla uygulayınız. Şu ana kadar mevcut bir dizi üzerinden nasıl slice oluşturabileceğimizi ve çeşitli veri kesme yöntemlerini inceledik. Şimdi de bir slice nesnesini herhangi bir diziden bağımsız olarak nasıl oluşturabileceğimize bakalım. Bir Diziden Bağımsız Olarak Yeni Bir Slice Oluşturmak Go dili yazılım geliştiricilerinin slice’lar ile olabildiğince esnek çalışabilmelerini sağlamak için slice’lara birçok özellik ve esneklik eklemiştir. Bunlardan biri de, slice’ların dizilerden bağımsız olarak kullanılabilmesidir. Bu konuya teknik olarak bakacak olursak, aslında slice’ın bilgisayar belleğinde veri depolayabilmek için dizilere ihtiyaç duyar. Bu nedenle, biz yeni bir slice oluşturduğumuzda, Go derleyicisi arka planda bu slice için bir dizi oluşturarak, slice’ları bağımsız şekilde kullanabilmemize izin vermektedir. Şimdi bu yöntemi uygulayarak yeni bir slice oluşturalım. Örnek: Uygulayacağımız örnek mevsimler ve aylar ile ilgili olacak. Yeni bir slice oluşturacağız ve yılın 12 ayını bu slice’a ekleyeceğiz. Sonrasında bu slice üzerinden farklı slice’lar oluşturarak bu ayları mevsimlere göre ayıracağız. months := [...]string{ 1: "Ocak", 2: "Şubat", 3: "Mart", 4: "Nisan", 5: "Mayıs", 6: "Haziran", 7: "Temmuz", 8: "Ağustos", 9: "Eylül", 10: "Ekim", cihanozhan.com
  • 22. 11: "Kasım", 12: "Aralık"} Not : months dizişi 13 eleman kapasitesine sahiptir(cap/len(months) ile kontrol edin). Ancak biz ay numaralandırmasını bir(1)’den başlatabilmek için sıfırıncı(0) index’i kullanmadık. Bu sayede, daha kolay okunabilir ve yönetilebilir bir slice’a sahip olduk. Yukarıdaki months slice’ını oluştururken köşeli parantezler içerisinde üç nokta kullandık([…]). Bunun nedeni, yeni slice’ımızın kapasitesini, başlangıçtaki atanan elemanların dinamik olarak belirlemesini sağlamaktı. Not : Bu örnekte kullanılacak eleman sayısı sabit olduğu için burada sabit bir değer de kullanabilirsiniz. Ayları mevsimlere ayırma uygulamamıza adım adım devam ederken, şimdi 12 ay verisini üçerli gruplardan oluşacak şekilde 4 mevsime bölelim. Bu işlemi birinci aydan onikinci aya kadar olacak şekilde baştan başlayarak yapacağız. p1 := months[1:4] // Ocak, Şubat, Mart p2 := months[4:7] // Nisan, Mayıs, Haziran p3 := months[7:10] // Temmuz, Ağustos, Eylül p4 := months[10:13] // Ekim, Kasım, Aralık Not : p1, p2 şeklinde p ile başlayan isimlendirmenin açılımı part’tır. Yılın ilkbahar aylarını, spring adında bir slice oluşturarak ayıralım. spring := p1[2:3] // 3. ayı ilkbahara ait olduğu için aldık springSub := p2[0:2] // 4. ve 5. ayları ilkbahara ait oldukları için aldık for _, month := range springSub { spring = append(spring, month) } fmt.Println("İlkbahar: ", spring) İlkbahar aylarının çıktısı: İlkbahar: [Mart Nisan Mayıs] Yılın yaz aylarını, summer adında bir slice oluşturarak ayıralım. summer := p2[2:3] // 6. ayı yaza ait olduğu için aldık summerSub := p3[0:2] // 7. ve 8. ayları yaza ait oldukları için aldık for _, month := range summerSub { summer = append(summer, month) } fmt.Println("Yaz: ", summer) Yaz aylarının çıktısı: Yaz: [Haziran Temmuz Ağustos] Yılın sonbahar aylarını autumn adında bir slice oluşturarak ayıralım. autumn := p3[2:3] // 9. ayı sonbahara ait olduğu için aldık autumnSub := p4[0:2] // 10. ve 11. ayları sonbahara ait oldukları için aldık for _, month := range autumnSub { cihanozhan.com
  • 23. autumn = append(autumn, month) } fmt.Println("Sonbahar: ", autumn) Sonbahar aylarının çıktısı: Sonbahar: [Eylül Ekim Kasım] Yılın kış aylarını winter adında bir slice oluşturarak ayıralım. winter := p4[2:3] // Yılın son ayı kışa ait olduğu için aldık winterSub := p1[0:2] // Yılın ilk iki ayı kışa ait olduğu için aldık for _, month := range winterSub { winter = append(winter, month) } fmt.Println("Kış: ", winter) Kış aylarının çıktısı: Kış: [Aralık Ocak Şubat] Yılın aylarını mevsimlere göre ayırma uygulamamızı tamamladık. Artık ilgili slice’ları istediğiniz gibi kullanarak mevsimlere göre işlemler yapabilirsiniz. Ancak, sanki biraz uzun bir kodlama oldu gibi! Mesela her işlem için ayrı ayrı for döngüsü oluşturarak slice’ları birbiriyle birleştirdik. Aslında bu işlem yerine bir metot oluşturarak 4 farklı işlem için tek bir metot kullanabilirdik. Bu bir yöntemdi… Ancak henüz metotları incelemedik ve metotların önemini anlamak için bu tür sorunları yaşamak gerekiyor! Merak etmeyin! Başka bir yöntem daha mevcut! Şimdi bunu yeni yöntemi summer slice’ı için yaptığımız örneğin alternatifi olarak yapalım. Kısa Kod: Yılın yaz aylarını summer adında bir slice oluşturarak ayıralım. spring := p1[2:3] springSub := p2[0:2] // for döngüsü ile yaptığımız işlemin aynısını tek başına yapan kod! summer = append(summer, summerSub...) Kıssadan Hisse : Eğer kullandığınız programlama dili ve platformu iyi tanımazsanız, bu örnekte olduğu gibi daha fazla kod yazmanız gerekebilir ve hatta bazen çözümsüz kalabilirsiniz. İki Slice İçerisindeki Kesişen Verileri Bulmak Gerçek dünya uygulamaları geliştirirken slice’lar ile çok sık oynamanız gerekecek. Biz de gerçek bir ihtiyaçtan yola çıkarak, küçük bir kesişen verileri bulma uygulaması yaparak slice’lar ile oynayalım. Bazı isimler sadece erkek çocukları için, bazıları sadece kız çocukları için kullanılır. Ancak bazı isimler unisex olarak tanımlanırlar. Yani, bu isimleri hem erkek çocukları hem de kız çocukları kullanabilir. Biz de elimizdeki veri seti üzerinde unisex isimleri bulmak için küçük bir algoritma çalıştıracağız. Bu uygulamayı gerçek dünya uygulaması haline getirmek de mümkündür. Sadece elinizde Türk unisex isimleri listesinin olması yeterlidir. Örnek: girlNames := [4]string{"Ayşe", "Fatma", "Doğa", "Deniz"} boyNames := [4]string{"Kadir", "Ahmet", "Deniz", "Doğa"} cihanozhan.com
  • 24. unisexName := "" for _, girlName := range girlNames { for _, boyName := range boyNames { if girlName == boyName { unisexName = girlName fmt.Printf("%s unisex bir isimdir.n", unisexName) } } } Örnek çıktısı: Doğa unisex bir isimdir. Deniz unisex bir isimdir. Bir Slice Üzerindeki Verilerde Değişiklik Yapmak Bilgisayar hafızası üzerindeki verilerde hızlı bir şekilde değişiklikler yapabilmek önemlidir. Örneğin, bir slice’da bulunan verilerde çok fazla kod yazmadan değişiklikler yapabiliriz. Sorun : Elimizde 10 adetlik bir kullanıcı listesi var. Bu kullanıcı listesindeki kullanıcıların son 5 tanesinin yaş bilgisi sisteme yanlış girilmiş. Bu 5 kullanıcıyı bulup, yaş bilgilerinin bir artırılması gerekiyor. Örnek: ages := [...]int{32, 43, 18, 54, 22, 21, 34, 19, 59, 36} changeThat := ages[5:10] fmt.Println("Verinin İlk Hali: ", ages) for i := range changeThat { changeThat[i]++ } fmt.Println("Verinin Son Hali: ", ages) Örnek sonucu: Verinin İlk Hali: [32 43 18 54 22 21 34 19 59 36] Verinin Son Hali: [32 43 18 54 22 22 35 20 60 37] Çok Boyutlu Slice Kullanımı Diziler konusundan hatırlayacağınız çok boyutlu çalışabilme yeteneğini bir slice üzerinde de uygulayabiliriz. Şimdi, çok boyutlu slice’lar ile nasıl çalışabileceğimize bir bakalım. Örnek: programmingLanguages := [][]string{ {"C", "C++"}, {"C#", "Java"}, {"JavaScript", "Rust"}, {"Go", "Erlang"}, cihanozhan.com
  • 25. } for _, loop1 := range programmingLanguages { for _, loop2 := range loop1 { fmt.Printf("%s ", loop2) } fmt.Printf("n") } Örnek sonucu: C C++ C# Java JavaScript Rust Go Erlang Bir Slice’ın Nil Durumunu Kontrol Etmek Go dilinde nesnelerin null olma durumu nil ile yönetilir. Ve her slice’ın başlangıç değeri varsayılan olarak nil’dir. Eğer bir slice’ın başlangıcında değer aldığını algoritmik olarak garanti edemiyorsak, o zaman slice için bir nil kontrolü yapmalıyız. Not : Go dilinde hata yönetimini “Hata Yönetimi” bölümünde derinlemesine inceleyeceğiz. Ancak yeri gelmişken, slice ile ilgili küçük bir bilgi notu olarak bu eklemeyi yapmayı uygun gördük. Örnek: var names []string if names == nil { names = append(names, "Cihan", "Barış", "Erdal") fmt.Println("İsimler: ", names) } Örnek sonucu: İsimler: [] İsimler: [Cihan Barış Erdal] Yukarıdaki işlem gayet basittir. Slice’ı if ile kontrol ederek nil olup olmadığına bakıyoruz. Eğer slice’ın değer durumu nil ise if scope’u içerisinde slice’a değer ekliyoruz. cihanozhan.com
  • 26. Map Map nesneleri, Go dilindeki unordered key/value pair koleksiyonlardır. Her Map nesnesinin key ve value alanları bulunur. Key/value pair nesne modelinin yapısı gereği, key alanları benzersiz bir anahtar içermelidir. Value alanları ise herhangi bir veri yapısında olabilir. Bir Map nesnesini oluşturmak için make() fonksiyonu kullanılır. Map nesnelerinin başlangıç değerleri nil’dir. Bir Map nesnesinin key ve value alanları farklı veri tiplerine sahip olabilir. Map Kullanımı İlk örneğimizde key ve value alanlarının ikisini de string veri tipiyle tanımlayan bir örnek yapacağız. Örnek: states := make(map[string]string) // Map nesnesini oluştur fmt.Println("Boş : ", states) // nil değere sahip map nesnesini ekrana bas Örnek çıktısı: Boş : map[] Şimdi de oluşturduğumuz states isimli Map nesnesine birkaç şehir verisi ekleyelim. Örnek: states["IST"] = "İstanbul" // Benzersiz olan IST anahtarına Istanbul verisini ekler states["ANK"] = "Ankara" states["ANT"] = "Antalya" fmt.Println("Dolu : ", states) Örnek çıktısı: Dolu : map[IST:İstanbul ANK:Ankara ANT:Antalya] Bir Map’in Elemanlarına Erişim Oluşturduğumuz states adındaki Map nesnesinin bir elemanına erişelim. Örnek: antalya := states["ANT"] fmt.Println("Seçili Şehir : ", antalya) Map’in bir elemanına erişmek için mapName[key] yapısını kullanmak yeterlidir. Örnek çıktısı: Seçili Şehir : Antalya Bir Map Nesnesinden Eleman Silmek Map nesnesinden eleman silmek için Go’nun built-in fonksiyonlarından delete()’i kullanıyoruz. Örnek: delete(states, "ANK") cihanozhan.com
  • 27. fmt.Println(states) Örnek çıktısı: map[IST:İstanbul ANT:Antalya] Döngü ile Map Verisine Erişim Map nesneleri genellikle birden fazla veriye sahip oldukları için, bu nesne üzerinde iteration(yineleme) işlemleri uygulamak önemlidir. Şimdi bir Map nesnesini döngü ile nasıl kullanabileceğimize bakalım. Öncelikle, states nesnesinin eleman adedini artırmak için bir eleman daha ekliyoruz. states["ERZ"] = "Erzurum" Örnek: for key, value := range states { fmt.Printf("%v: %vn", key, value) } Örnek çıktısı: IST: İstanbul ERZ: Erzurum ANT: Antalya Yukarıdaki döngü işleminde states isimli Map üzerinden key ve value değerlerini alarak ekrana yazdırdık. Burada kullandığımız key ve value tanımlamaları kodun anlaşılması için tercih edilen isimlerdir. Bu alanlar için istediğiniz isimlendirmeyi kullanabilirsiniz. Ayrıca bazı durumlarda sadece value değerlerini elde etmek isteyebilirsiniz. Bu tür durumlarda key yerine altçizgi( _ ) kullanarak sadece value nesnesine erişmek istediğinizi derleyiciye bildirmiş olursunuz. Aynı kural value nesnesi için de geçerlidir. for _, value := range states ya da for key, _ := range states Şimdi de, gene döngüleri kullanarak Map nesnesi üzerinde farklı bir işlem yapalım. İstek: states isimli Map nesnesinin eleman sayısı kapasitesine sahip bir key list oluşturun. Örnek: keys := make([]string, len(states)) i := 0 for k := range states { keys[i] = k i++ } fmt.Println(keys) cihanozhan.com
  • 28. Örnek çıktısı: [ANT IST ERZ] Peki bu key listesini alfabetik olarak sıralayabilir miyiz? Sıralama işlemi Go built-in paketlerinden sort ile çok kolay… Örnek: sort.Strings(keys) Örnek çıktısı: [ANT ERZ IST] Sıraladığımız key’lerin index değerlerine göre states nesnesindeki şehirleri yazdıralım. Örnek: for i := range keys { fmt.Println(states[keys[i]]) } Örnek çıktısı: Antalya Erzurum İstanbul Map İçerisindeki Bir Elemanın Varlığını Kontrol Etmek Bazı durumlarda eldeki veriyi koleksiyon nesnelerindeki verileri karşılaştırarak verinin varlığını kontrol etmek gerekebilir. Bu tür işlemler, normal arama ve bulma fonksiyonlarıyla yapılırken çok maliyetli olabilir. Ancak key/value pair koleksiyon modelinde bu tür bir işlemi key üzerinden düşük maliyet ile yapabilmekteyiz. Örnek: state, ok := states["ANK"] if !ok { fmt.Println("Aranan veri bulunamadı!") return } fmt.Println(state) Yukarıdaki örnekte, states isimli Map nesnesinin ANK adında bir key’e sahip olup olmadığını kontrol ediyoruz. Eğer bu Map nesnesi ANK isimli bir key’e sahipse, sol kısımda tanımladığımız ok değişkenine true değerini, state değişkenine de eşleşen key’in value değerini dönecektir. Eğer bu eşleşme gerçekleşmezse, ok değişkenine false değerini dönecektir. Örnek sonucu: Ankara Yukarıdaki işlemde states içerisinde olmayan bir veriyi kontrol etmeyi deneyin. Ekrana “Aranan veri bulunamadı.” mesajı basılacak ve hemen altındaki return komutu ile de işlem sonlandırılacaktır. cihanozhan.com
  • 29. Bu yöntemin daha doğru kullanımı şu şekildedir: Örnek: state, ok := states["ANK"] if ok { fmt.Println(state) } Yani, eğer Map içerisinde ANK ile eşleşen bir eleman varsa bunu ekrana bas, yoksa herhangi bir şey yapmana gerek yoktur. type Anahtar Kelimesi Daha önce, Go dilinin yazılım geliştirme süreçlerindeki sıkıntılara odaklandığını belirtmiştik. type anahtar kelimesi de, bu tür sorunlardan birine çözüm olmak için dile eklenen bir özelliktir. En temel anlamda düşünürsek, Go kod dosyalarınızda tanımladığınız değişkenlerdeki kompozit(composite) tipleri sonradan değiştirmek(redeclare) gibi süreçler baş ağrıtıcı olabilir. Bu nedenle, bu tür tipleri tanımlarken type anahtar kelimesini kullanmak, sonradan revize etme gibi işlemlerde işinizi kolaylaştırabilir. Biraz karmaşık gibi görünse de, bu konuyu örneklerle inceleyeceğiz. Söz dizimi: Tekli type typeName underlying-type Söz dizimi: Çoklu type ( typeName1 sourceType1 typeName2 sourceType2 ) type ile ilgili temel tanımlar: - Yeni tanımlanan tip(typeName1 gibi) ile, onun altında yatan sourceType1(int gibi) tipleri aynıdır. - Aynı alt tipler ile tanımlanan tipler birbirlerine dönüştürülebilir. - type ile oluşturulacak tipler fonksiyonların gövdesinde tanımlanabilir. type Kullanımı Genel olarak type anahtar kelimesinin amacını anladığımıza göre, şimdi type ve farklı birçok veri tipini kullanarak oluşturacağımız örnekleri inceleyebiliriz. type ile kullanabileceğimiz bazı Go dili nesnelerini henüz incelemedik. Ancak type ile neler yapılabileceğini anlamak adına bu örnekleri de bu başlık altında görebileceksiniz. type anahtar kelimesinin en temel kullanımı şu şekildedir: type Age int Bu basit tanımlamada Age adında bir tip oluşturarak bu tipin arka planda bir integer ile temsil edileceğini belirtmiş olduk. Bunun anlamı, Age’in veri tipi de kapasitesi de integer ile aynıdır. type kullanımına çoklu tanımlama örneği olarak ise: cihanozhan.com
  • 30. type ( Name string Age int ) Bu tanımlama yönteminin temel amacı, birden fazla type nesnesinin dağınık olarak oluşturulmaktansa, daha okunabilir ve düzenli olmasını sağlayacak şekilde bir arada tanımlanmasını sağlamaktır. Çoklu type bloğu içerisinde farklı veri tiplerine sahip birden fazla type nesnesi oluşturabilirsiniz. Şimdi type anahtar kelimesinin farklı tipler ile nasıl kullanılabileceğine bir göz atalım. type anahtar kelimesini bir sonraki bölümde inceleyeceğimiz struct nesneleriyle birlikte de sık sık kullanacağız. Buna da basit bir örnek verebiliriz: Örnek: type Video struct { ID, Time int Trainer, Title string } type anahtar kelimesini gene sonraki bölümlerde inceleyeceğimiz fonksiyonlar ile birlikte de kullanabileceğiz. Örnek: type Convert func(inputFile int, isFast bool) (convertedFilePath string, err error) type anahtar kelimesini daha önceki bölümlerde incelediğimiz dizi ve slice nesneleriyle birlikte de kullanabiliriz. Go dili bu konuda çok esnek ve çeşitliliğe sahiptir. Hatırlarsanız, değişken ve nesne tanımlamada var adında bir tanımlayıcı ve özel bir var scope’una sahiptik. Aynı şekilde var ile tanımlayabildiğimiz bu nesneleri type ile de tanımlayabiliyoruz. Örnek: Dizi için… type Articles [5]string Örnek: Slice için… type Comments []string Tanımlı Tipler & Tanımlanmamış Tipler Go 1.9 versiyonu öncesinde tip tanımlaması üzerinde herhangi bir ayrım yapmamıza gerek yoktu. Ancak Go 1.9’dan sonra eklenen yeni kullanım yöntemiyle birlikte bir ayrım yapmamız gerekiyor. Go 1.9 öncesinde kullandığımız yönteme zaten tanımlı tipler diyorduk. Go 1.9 sonrasında ise tanımsız(non- defined type) diyebileceğimiz yeni bir kullanım yöntemi eklendi. Şimdi bir alias tip oluşturarak tanımsız tiplere örnek verelim. cihanozhan.com
  • 31. Örnek: type ( ID = int Name = string ) Yukarıdaki alias tipi kullanımının diğer kullanımdan farkı, tanımlayıcı isim ile veri tipi arasındaki eşittir(=) işaretidir. Bu nedenle, eğer alias tipi olarak bir type tanımlayacaksanız aradaki eşittir(=) işaretini koymayı unutmamalısınız. Peki bu yöntemi nasıl ve neden kullanırız? Örnek: Kullanıcının adını ve veritabanındaki ID bilgisini tutacak bir Map değişkeni oluşturmak istediğimizi düşünelim. Bu örnek aşağıdaki gibi olabilirdi: type users = map[string]int Kullanıcının isim bilgilerini users adındaki Map nesnesinin değer alanında, kullanıcının ID bilgilerini ise key alanında tutabiliriz. Peki bu kullanımı biraz daha kullanıcılar verisinin yapısına göre tasarlamak istersek? type users = map[Name]ID Sanırım son oluşturduğumuz users Map nesnesinin biraz daha açık ve kullanıcı verisine göre özelleştirilmiş olduğu konusunda hemfikiriz. Şimdi tanımlı ve tanımsız tipleri karşılaştırarak bu konuyu sonlandıralım. Örnek: type Tip1 []string // Tip1 tanımlı tiptir. type Tip2 = Tip1 // Tip2 nesnesi Tip1 nesnesiyle eşitlendi! // Bu nedenle Tip2'de tanımlı bir tiptir. type Tip3 = []string // Alias type(Tip3) ve []string tanımsız tiptir. type Dönüştürme type anahtar kelimesini tanımlarken, aynı alt veri tipine sahip type tiplerinin birbirlerine dönüştürülebileceğinden bahsetmiştik. Şimdi bunu nasıl yapabileceğimize bir bakalım. Örnek: Hatalı! type age int16 var newAge int16 = 27 var UserAge age = newAge Yukarıdaki örnekteki ilk satırda, int16 veri tipine sahip age adında bir tip oluşturduk. İkinci satırda ise, newAge adında ve int16 veri tipine sahip bir değişken oluşturduk ve bu değişkene 27 değerini atadık. Üçüncü ve son satırda ise, yeni oluşturduğumuz UserAge adındaki bir değişkene veri tipi olarak ilk satırda oluşturduğumuz age adındaki tipi atadık. Ve bu UserAge değişkenine, age tipiyle aynı veri tipine sahip olan newAge değişkenini atadık. cihanozhan.com
  • 32. Yukarıdaki örneği çalıştırmanıza gerek kalmadan hata verdiğini ve VSCode editörünün hatalı kodun altını kırmızıyla çizdiğini görebilirsiniz. Bunun nedeni, age tipi ile newAge değişkenlerinin aynı veri tipine(int16) sahip olsalar bile, derleyici tarafından karıştırılmasıdır. Derleyici bu iki nesnenin de aynı tipe sahip olduğunu bilse bile, bu nesneleri birbirine atayabilmek için explicit conversion işlemi uygulanmasını şart koşuyor. Yani, bu tipleri birbirine atamak istediğimizi özel olarak belirtmemiz gerekiyor. Peki nasıl? Örnek: type age int16 var newAge int16 = 27 var UserAge age = age(newAge) Yukarıdaki örneği çalıştırdığınızda ekrana 27 değerinin basıldığını görebilirsiniz. Dikkat ederseniz, son örneğimizin diğer örnekten tek farkı newAge değişkeni üzerinde uygulanan age tipine dönüştürme işlemidir. Bu dönüştürmeyi de açık bir şekilde age(newAge) diyerek gerçekleştirdik. cihanozhan.com