2# Go Programala Dili — Sözdizimi (Syntax) ve Veri Tipler

Nailcan Küçük
9 min readJan 15, 2020

Bu yazıda Go Programlama diline ait sözdizimi, tip, anahtar kelimeler, değişken tanımlama, sabitler gibi temel yapılardan bahsetmeye çalışacağım. Ayrıca string değişlenlerdeki UTF-8 desteğinden de örnekler ile bahsedeceğim.

Go Programlama dilinde toplam 25 adet keyword vardır. Diğer programlama dilleri ile karşılaştırıldığında en az keyword’e sahip dillerden birisidir Go. Bazı temel diller için keyword sayıları aşağıdaki gibidir.

  • C++: 82
  • C#: 79
  • Java: 50
  • JavaScript: 38
  • Phyton 3.7: 35
  • Dart: 54

Go dilindeki keyword listesi aşağıdaki gibidir:

break    default     func   interface select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import

Operatör ve sınırlayıcılar ise 47 adettir.

+   &   +=  &=   &&  ==  !=  (  )
- | -= |= || < <= [ ]
* ^ *= ^= <- > >= { }
/ << /= <<= ++ = := , ;
% >> %= >>= — ! … . :
&^ &^=

Değişken Tanımlama

Go dilinde değişken tanımlaması yapmak için birçok yöntem vardır. Bunlardan ilki bir değer ataması yapmadan tanımlama şekli. Bu durumda değişken, tipine göre varsayılan değerine sahip olur.

var t int

İstersek değişken tanımlama esnasında = operatörü ile değer ataması da yapabiliriz.

var t int = 10

Kısa değişken tanımlaması olarak adlandırabileceğimiz bir yöntem daha vardır. Bu tanımlamada := operatörü kullanılır ve değişken tanımlanırken bir değer atanması zorunludur.
Lokal değişken olarak kullanılır. Sadece ilk tanımlamasının yapıldığı alan içerisinde geçerliliği vardır. Yani bir fonksiyon içerisinde tanımlandıysa sadece o fonksiyon içerisinde, yada fonksiyon içerisindeki bir döngü oluşturulurken tanımlandıysa sadece o döngü içerisinde geçerlidir.

t := 10

Eğer tanımlama esnasında tip belirtmek istenirse değişken wrap edilerek oluşturulabilir.

t := int64(10)

Eğer değişken tanımlaması yapılırken bir değer ataması yapılmamış ise, değişkene sıfır değeri (zero value diye geçiyor) atanır.

Veri tipleri için sıfır değerleri:

  • Numerik veri tipleri için: 0
  • Boolean veri tipi için: false
  • String veri tipi için: “” (boş string)

Değişken değeri için bazı dillerde undefined yani tanımsız değer vardır. Ancak Go da undefined değer yoktur. Örneğin bool veri tipi için Go’da alabileceği true veya false olarak 2 değer vardır.

package mainimport “fmt”func main() {
var name string
fmt.Printf(“var name %T = %+v\n”, name, name)
var payment float64
fmt.Printf(“var payment %T = %q\n”, payment, payment)
var isActive bool
fmt.Printf(“var isActive %T = %+v\n”, isActive, isActive)
}

Çıktısı:

var name string = “”
var payment float64 = 0
var isActive bool = false

Değişken İsimlendirme

Go programlama dilinde diğer birçok dilde olan private, public, protected gibi erişim belirleyici keyword’ler yoktur. Bu durumu da daha sade bir yol ile çözmüşler.

Eğer değişken ismi büyük harf ile başlıyor ise bu değişken tanımlı olduğu paket dışından da erişilebilir oluyor. Ancak küçük harf ile başlıyorsa sadece tanımlı olduğu paket içerisinde erişilebilir oluyor.

Bu nedenle değişken isimlendirmesi case-sensitive dir diyebiliriz.

var FirstName string
var password string

Değişken isimlendirken dikkat edilmesi gereken diğer noktalar şunlardır:

  • Sadece harf, numara ve alt çizgi kullanılarak yapılmalıdır.
Doğru -> user_name, userName, signal4
Yanlış -> best.offer, user-name
  • Bir numara ile başlamamalıdır
Doğru -> best4Game, house62
Yanlış -> 10cars
  • Sembol kullanılmamalıdır
Doğru -> product
Yanlış -> $product

Çoklu Atama

Go ile birden fazla değişkene tek satırda farklı data tipinde değer ataması yapılabilmektedir. Özellikle kod okunurluğunu açısından çok kolaylık sağlayan bir özelliktir.

a,b,c := 12, true, “Google”fmt.Println(a)
fmt.Println(c)
fmt.Println(b)

Çıktısı:

12
Google
true

Numerik Tipler

Go dilinde 2 farklı numerik tip vardır. Bunlar mimariden bağımsız (architecture independent type) olarak doğru boyut alan ve programın oluşturulduğu mimariye bağlı (implementation specific type) olarak boyut alan tipler olarak ayrılabilir.

Mimari bağımsız tipler:

uint8  işaretsiz 8-bit  tamsayı (0–255)
uint16 işaretsiz 16-bit tamsayı (0–65535)
uint32 işaretsiz 32-bit tamsayı (0–4294967295)
uint64 işaretsiz 64-bit tamsayı (0–18446744073709551615)
int8 işaretli 8-bit tamsayı (-128–127)
int16 işaretli 16-bit tamsayı (-32768–32767)
int32 işaretli 32-bit tamsayı (-2147483648–2147483647)
int64 işaretli 64-bit tamsayı (-9223372036854775808–9223372036854775807)
float32 IEEE-754 Standartı 32-bit ondalıklı sayı (+- 1O-45 -> +- 3.4 * 1038 )float64 IEEE-754 Standartı 64-bit ondalıklı sayı (+- 5 * 10–324 -> 1.7 * 10308 )complex64
complex128
byte ~~ uint8
rune ~~ int32

Mimari bağımlı tipler

uint    -> 32 veya 64 bit
int -> uint ile aynı boyutta
uintptr -> işaretçi değerinin yorumlanmamış bitlerini depolayacak kadar büyük, işaretsiz bir tam sayı

Mimari bağımlı tiplerin boyutları, hangi sistem için derlendiklerine göre değişiklik gösterecektir.

Özellikle mimari bağımsız tiplerin kullanımında, doğru tipin seçilmesi uygulama performansını etkileyen bir seçim olacaktır. Örnek olarak sadece 0–200 arası sayıları kullacaksak uint yerine uint8 tipinde değişkenimizi tanımlamak doğru olan kullanımdır.

Burada da dikkat etmemiz gerek başka bir husus kodumuzun akışı içerisinde veri tipi boyutunu aşmaması gerektiğidir.

Örnek 1: Değer aralığı içerisinde, doğru sonuç vermesi durumu

package mainimport (
“fmt”
)
func main() {
var t uint8 = 254
fmt.Println(t + 1)
}

Çıktısı:

255

Örnek 2: Değer aralığı dışına çıkıyor. Hata sonucu ekrana basma kısmında oluyor. Geriye 0 dönüyor.

package mainimport (
“fmt”
)
func main() {
var t uint8 = 254
fmt.Println(t + 2)
}

Çıktısı:

0

Örnek 3: Değer aralığı dışına çıkıyor. Hatayı toplama işlemi sonrası değer atması esnasında yaşıyor. Hata mesajı fırlatıyor.

package mainimport (
“fmt”
)
func main() {
var t uint8 = 254 + 2
fmt.Println(t)
}

Çıktısı:

./prog.go:8:20: constant 256 overflows uint8

Boolean

Boolean veri tipi true veya false olmak üzere 2 farklı değer alabilir. Varsayılan değeri false ‘dur. Kod akışı içerisindeki kontrol mekanizmalarında kullanışlıdır.

package mainimport (
“fmt”
)
func main() {
var isActive bool
printed := true
fmt.Println(isActive)
fmt.Println(printed)
}

Çıktısı

Output:
false
true

String

String veri tipleri, bir veya daha çok karakterin sıralı olarak bir araya gelmesiyle oluşur.

Go dilinde string ifadeler çift tırnak (“) veya tek ters tırnak (`) karakterleri arasında yazılabilir.

a := “Sabah görünce \”Merhaba\” dedi”
b := `Sabah görünce “Merhaba” dedi`

UTF-8

Go dili kendi içerisinde UTF-8 desteği ile gelir. Ayrıca bir paket, kütüphane .. vs ihtiyaç duymaz.

UTF-8 karakter desteğini aşağıdaki örnek kod ile test edebilirsiniz.

package mainimport (
“fmt”
)
func main() {
a := “Hello, 世界”
for i, c := range a {
fmt.Printf(“%d: %s\n”, i, string(c))
}
fmt.Println(“length of ‘Hello, 世界’: “, len(a))
}

Çıktısı:

0: H
1: e
2: l
3: l
4: o
5: ,
6:
7: 世
10: 界
length of ‘Hello, 世界’: 13

Görüldüğü gibi a değişkeninin uzunluğu, a değişkenindeki karakter sayısından daha fazla çıkmıştır. Bunun nedeni Go dilindeki özel bir tip olan rune tipi ile ilgilidir. Rune karakterlerin unicode değerini içerisinde bulunduran, 1–3 arası int32 tipinde değerden oluşan özel bir tiptir.

Rune değeri ile ilgili olarak aşağıdaki örnek incelenebilir.

package mainimport “fmt”func main() {
const nihongo = “日本語”
for index, runeValue := range nihongo {
fmt.Printf(“%#U starts at byte position %d\n”, runeValue, index)
}
}

Çıktısı:

U+65E5 ‘日’ starts at byte position 0
U+672C ‘本’ starts at byte position 3
U+8A9E ‘語’ starts at byte position 6

Constants

Constant’lar tanımlanması esnasında atanan ilk değerinin sonradan değiştirilmesine izin vermeyen değişken tipleridir.

package mainimport “fmt”func main() {
const gopher = “Nail”
fmt.Println(gopher)
}

Çıktısı:

Nail

Eğer bir constant değerini tanımlandıktan sonra değiştirmek isterseniz derleme esnasında hata alırsınız.

package mainimport “fmt”func main() {
const gopher = “Nail”
fmt.Println(gopher)
gopher = “Can”
fmt.Println(gopher)
}

Çıktısı:

./prog.go:10:9: cannot assign to gopher

Typed & Untyped Constants

Constant tanımlarken, değişkeni veri tipini belirterek veya belirtmeyerek tanımlama yapılabilir. Eğer değişken veri tipi belirtilmemiş ise bile değer ataması esnasında anlık olarak constant veri tipi belirlenir.

Typed ve Untyped Constant tanımlaması ile ilgili örnek kod aşağıdaki gibidir:

package main

import “fmt”const (
year = 365 // untyped
leapYear = int32(366) // typed
)
func main() {
hours := 24
minutes := int32(60)
fmt.Println(hours * year)
fmt.Println(minutes * year)
fmt.Println(minutes * leapYear)
}

Çıktısı:

8760
21900
21960

Eğer typed bir constant’a belirtilenden farklı bir tipte bir değer ataması yapılmak istenirse derleme esnasında hata alacaktır.

package mainimport “fmt”const (
leapYear = int32(“test”) // typed
)
func main() {
minutes := 10
fmt.Println(minutes * leapYear)
}

Çıktısı:

./prog.go:6:18: cannot convert “test” (type untyped string) to type int32

Iota

Artan sayılara sahip constant tanımlamasında kullanılan bir tiptir. Tanım sırasına göre artırarak değer ataması yapar. Tanımlandığı blok içerisinde 0’dan başlar ve 1’er artarak devam eder.

package mainimport “fmt”const (
Metin int = iota
Ali
Feyyaz
)
func main() {
fmt.Printf(“Metin is %v\n”, Metin)
fmt.Printf(“Feyyaz is %v\n”, Feyyaz)
fmt.Printf(“Ali is %v\n”, Ali)
}

Çıktısı:

Metin is 0
Feyyaz is 2
Ali is 1

Konsol Çıktısı Oluşturma

Konsol çıktıları oluşturabilmek için kaynak kod içerisinde fmt paketinden yararlanabiliriz. fmt paketini import ettikten sonra paket içerisindeki Print, Printf ve Println fonksiyonları ile çıktılar oluşturabiliriz. Ayrıca Errorf, Fprint, Fprintf, Fprintln, Sprint, Sprintf, Sprintln fonksiyonları ile de çıktılar oluşturulabilir.

Şimdilik temel kullanım olarak;

  • Eğer standart bir string ifadeyi çıktı olarak kullanacaksak Println fonksiyonunu kullanabiliriz.
  • Eğer çıktımıza bazı değerleri parametre olarak geçeceksek ve/veya bu parametre olarak geçilen değerleri formatlayarak göstereceksek Printf kullanmalıyız.

Bu paket ayrıca konsol üzerinden veri okumamıza yarayan (scan) fonksiyonlar da içermektedir.

package mainimport “fmt”func main() {
fmt.Println(“Bu kodlar zaten miras kaldı bana.”)
fmt.Printf(“Hep %s suçu \n”, “bir önceki yazılımcının”)
}

Çıktısı:

Bu kodlar zaten miras kaldı bana.
Hep bir önceki yazılımcının suçu

Fiiller (Verbs)

Tüm Print fonksiyonları fiilleri kullanabilir. Bu fiiller farklı biçimlendirme stilleri oluşturur. Fiiller genellikle % veya \ karakteriyle kullanılır.

Bazı fiiller şunlardır:

// %v -> tip kontrolü yapmadan değeri yazar
// %s -> string değerler için kullanılır
// %d -> numerik değerler için (int, int32, etc)
// %T -> veri tipini döner
// %f -> Ondalıklı değerler için
// \ -> escape karakteri
// \n -> bir alt satıra geçmek için kullanılır
// \t -> tab boşluğu bırakmak için kullanılır

Örnek Kod:

package mainimport (
“fmt”
)
func main() {
const adi, yasi, calisiyorMu, yemekUcreti = “Nail”, 32, true, 21.5
fmt.Printf(“Adı: %v \n”, adi)
fmt.Printf(“Yaşı: %v \n”, yasi)
fmt.Printf(“Çalışıyor mu : %v \n”, calisiyorMu)
fmt.Printf(“Yemek ücreti: %v”, yemekUcreti)
fmt.Println(“********”)
fmt.Printf(“Adı: %s \n”, adi)
fmt.Printf(“Yaşı: %d \n”, yasi)
fmt.Printf(“Çalışıyor mu : %t \n”, calisiyorMu)
fmt.Printf(“Yemek ücreti: %f”, yemekUcreti)
fmt.Println(“********”)
fmt.Printf(“Adı: %T \n”, adi)
fmt.Printf(“\t Yaşı: %T \n”, yasi)
fmt.Printf(“\t \t Çalışıyor mu : %T \n”, calisiyorMu)
fmt.Printf(“\t \t \t Yemek ücreti: %T”, yemekUcreti)
}

Çıktısı:

Adı: Nail 
Yaşı: 32
Çalışıyor mu : true
Yemek ücreti: 21.5********
Adı: Nail
Yaşı: 32
Çalışıyor mu : true
Yemek ücreti: 21.500000********
Adı: string
Yaşı: int
Çalışıyor mu : bool
Yemek ücreti: float64

Yorum Satırları

Go dilinde yorum satırları diğer birçok dil ile aynı yöntemler kullanılarak oluşturulmaktadır. Bu yöntemlerden en basiti iki adet slash karakterini satırın balına eklemektir.

// Yorum satırı…

Eğer bir satır bloğunu yorum satırı haline getirmek istiyorsak da bu satırların başına tek tek // ekleyebiliriz veya bloğun en başına /* ,en sonuna da */ karakterlerini ekleyerek içeride kalan satırları yorum satırı haline getirmiş oluruz.

/*
Bu satırların
hepsi
aslında yorum satırıdır
*/

Bir satırada satırın başına değil istediğimiz herhangi bir yerine de // karakterlerini ekleyerek satırda bu karakterlerden sonrasının yorum satırı olmasını sağlayabiliriz.

z := x % 2 // x’in 2 ile bölümünden kalanı verir

Bir uygulamanın dokümantasyonunun oluşturulması da çok önemlidir. Go dili tasarlanırken de yazılan kodun kolay dokümante edilebilmesini sağlamak amacı ile yorum satırlarından yararlanılması planlanmıştır. GoDoc oluşturulurken sizin kod içerisinde, fonksiyonlarınızın üzerinde yazdığınız yorum satırları kullanılmaktadır. Bu nedenle kod içerisindeki yorum satırlarına daha çok önem göstermek gerekmektedir.

GoDoc ile ilgili aşağıdaki bağlantıdan daha detaylı bilgi alabilirsiniz.

Structs

Go diline özgü veri tiplerinden birisi de structlardır.
Diğer dillerdeki model yapısına benzerlikleri vardır. İçerisinde alanlar barındıran bir veri topluluğudur.

type keyword’ü kullanılarak tanımlanır

type User struct {
Name string
Email string
}

Struct içerisindeki alanlara . karakteri ile erişebiliriz. Eriştiğimiz alan bize değerini döner. İstersek = ekleyerek ilgili alanın değerini değiştirebiliriz.

Tanımlı struct tipinde bir nesne oluşturmak için aşağıdaki yöntemlerin hepsi geçerlidir.

a := User{}b := User{
Name: “Homer Simpson”,
Email: “homer@example.com”,
}
c := User{Email: “marge@example.com”}
c.Name = “Marge Simpson”
d := User{Name: “Homer Simpson”, Email: “homer@example.com”}e := User{“Homer Simpson”,”homer@example.com”}fmt.Println(a.Name)
fmt.Printf(“User’s email is %s”, e.Email)

Fakat e değişkenini oluşturduğumuz yöntem tavsiye edilen bir kullanım biçimi değildir. Çünkü ileride User struct’ı içerisindeki bir değişiklik durumunda uygulamamızda aşağıdaki gibi bir hata almamız kaçınılmazdır.

type User struct {
ID int
Name string
Email string
}

Değişikliği sonrası konsol çıktısı:

too few values in User literal

Go dilini öğrenme sürecimde sözdizimi ve veri tipleri ile ilgili tuttuğum notları sade bir şekilde sizlerle paylaşmaya çalıştım. Bundan sonraki süreçlerde de yine aynı şekilde notlarımı bir seri olarak paylaşmayı hedefliyorum.

Umarım sizler için de faydalı olmuştur :)

Burada paylaştığım bilgiler çoğunlukla Google’ın Go Dili üzerine düzenlemiş olduğu Workshop’larda kullandığı sunumlardan ve Go resmi sayfasındaki dökümantasyon ve tur bölümündeki açıklamalardan edindiğim notları içermektedir.

İletişimde kalmak isterseniz linkedin üzerinden haberleşebiliriz.

--

--