Tag logo

Short notes about Golang

Oct 10, 2022/
#golang
/-7 min

Yaşayan Yazı, bir yerimden uydurduğum bir terimdir ve ileriki dönemde içeriği zenginleşebilecek ama şu anki haliyle de faydalı olabilecek yazıları belirtir.

Basics

  • Golang, C'ye benzer ancak sözdizimi daha basit, hızlıca derlenebilen ve multithread desteği sunan bir programlama dilidir. Çoğunlukla mikroservis uygulamalarında kullanılır.
  • Paketlerin dökümantasyonlarını görmek için
    go doc fmt
    , bir metodunun dökümantasyonu için de
    go doc fmt.Println
    komutları kullanılabilir.
1func Fprint(w io.Writer, a ...any) (n int, err error)
2func Fprintf(w io.Writer, format string, a ...any) (n int, err error)
3func Fprintln(w io.Writer, a ...any) (n int, err error)
4func Print(a ...any) (n int, err error)
5func Printf(format string, a ...any) (n int, err error)
6func Println(a ...any) (n int, err error)
7func Sprint(a ...any) string
8func Sprintf(format string, a ...any) string
9func Sprintln(a ...any) string
10...

Hello World

  • En basit Golang dosyasının yapısı aşağıdaki gibidir (kodu çalıştırmak için
    go run main.go
    ):
1// kod organizasyonu paketler ile sağlanır.
2// aynı klasör içinde bulunan dosyalarda paket ismi aynı olmalıdır.
3package main
4
5// kütüphaneler klasik şekilde dahil edilir.
6import "fmt"
7
8// programın giriş noktasıdır.
9// her pakette bir main fonksiyonu olabilir.
10func main() {
11  fmt.Println("Hello World")
12}
  • Farklı yazdırma fonksiyonları mevcuttur.
    Print
    ile başlayanlar stdout'a yani konsola çıktı verir ve byte sayısını döndürür.
    Fprint
    olanlar dosya ve tarayıcı gibi dış bir kaynağa,
    Sprint
    olanlar ise çıktıyı character buffer'da saklar. Yani değişkene çevirir.
1package main
2
3import "fmt"
4
5func main(){
6  fmt.Println("Hello!")
7  fmt.Print("Hello!\n")
8  fmt.Printf("Hi! My name is %s. I have lived in %s for %d years. They say the weather is amazing, which is %t", "Enes", "Bursa", 23, true)
9
10  // "Hello Enes!" metnini döndürür fakat konsola çıktı vermez.
11  result := fmt.Sprintf("Hello %s!", "Enes")
12}

Variables

  • Veri tipleri şunlardır:
    • Integer: int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64
    • Float: float32, float64
    • String: string
    • Boolean: bool
    • Null: nil
  • Birçok farklı şekilde değişken tanımlayabiliriz. Değişkene tip verebilir yada tahmin ettirebiliriz.
1// yöntem 1
2count := 10
3// yöntem 2
4var age = 21
5// yöntem 3
6var minute int = 60
7// yöntem 4: constant
8const MAX_COUNT = 10
9// yöntem 5
10var city string
11city = "Bursa"
  • Bir değişkenin türünü görmek için
    reflect.TypeOf()
    kullanabiliriz.
1stringVar := "string"
2intVar := 10
3floatVar := 1.2
4boolVar := false
5arrayVar := []string{"foo", "bar", "baz"}
6objectVar := map[string]int{"apple": 23, "tomato": 13}
7nilVar := nil
8
9fmt.Println(reflect.TypeOf(stringVar))
10fmt.Println(reflect.TypeOf(intVar))
11fmt.Println(reflect.TypeOf(floatVar))
12fmt.Println(reflect.TypeOf(boolVar))
13fmt.Println(reflect.TypeOf(arrayVar))
14fmt.Println(reflect.TypeOf(objectVar))
15fmt.Println(reflect.TypeOf(nilVar))
string
int
float64
bool
[]string
map[string]int
  • Golang'da değişken tip dönüşümleri için aynı isimde metodlar bulunur.
1floatNumber := 5.2
2intNumber := int(floatNumber)
3fmt.Println(intNumber)
5

Conditional Statements and Loops

  • if-else
    koşulunda JavaScript'in aksine parantez kullanılmaz.
1if num > 50 {
2  // ...
3} else if num > 20 {
4  // ...
5} else {
6  // ...
7}
  • Fonksiyonun hatasız çalıştığı durumlarda bir kod çalıştırmak için özel bir sözdizimi var.
1// err değişkeni sadece bu blok içinden erişilebilir.
2if err := someFunction(); err != nil {
3  fmt.Println(err.Error())
4}
  • switch
    yapısının iki kullanımı vardır. Eğer altındaki
    case
    ile ilerletmek istersek
    fallthrough
    kullanabiliriz.
1// birinci yol
2var status string = "ERROR"
3
4switch status {
5  case "WARN":
6    // ...
7  case "ERROR":
8    // ...
9  default:
10    // ...
11}
12
13// ikinci yol:
14var num int = 25
15
16switch {
17  case num < 50:
18    // ...
19  case num < 100:
20    // ...
21  default:
22    // ...
23}
  • for
    yapısının farklı kullanımları mevcuttur. Golang'de
    while
    yapısı mevcut değildr.
1for i := 1; i <= 100; i++ {
2  fmt.Println(i)
3}

Function

  • Fonksiyon tanımlamak için
    func
    anahtar kelimesi kullanılır. Parametre veyahut dönüş tipini tanımlarken TypeScript'ten farklı olarak iki nokta kullanmayız.
1package main
2
3import (
4	"fmt"
5	"time"
6)
7
8func main() {
9  fmt.Println(getAgeByYear(1999))
10}
11
12func getAgeByYear(yearOfBirth int) int {
13  return time.Now().Year() - yearOfBirth
14}
  • Fonksiyonlarda birden fazla değer döndürebiliriz.
1func getNumArray() (int, int)  {
2  return 4, 5
3}
  • Belirsiz sayıda argümanı koleksiyon olarak almak için
    ...
    operatörünü kullanabiliriz. Bu fonksiyonlara variadic function denir.

Range anahtar kelimesi indeks ve öğenin kendisini döner. İndeksi kullanmayacağımız için '_' kullanacağız aksi halde tanımlandı ancak kullanılmadı hatasını alırız.

1func printNames(names ...string) {
2  for _, name := range names {
3    fmt.Println(name)
4  }
5}

Array

  • Array'ler sabit boyutlu olmalıdır ya da başlangıç değeri tanımlanmalıdır. Yani
    [5]int != [4]int
    . Eğer girdiğimiz eleman kadar boyut alsın istersek yine
    ...
    operatörünü kullanabiliriz.
1var nums [5]int
2fmt.Println(nums)
3
4var nums2 [2]float64 = [2]float64{2.2, 3.8}
5fmt.Println(nums2)
6
7names := [4]string{"Ali", "Veli"}
8fmt.Println(names)
9
10names2 := [...]string{"Ali", "Veli", "Ahmet"}
11fmt.Print(names2)
12fmt.Println(" - type: ", reflect.TypeOf(names2))
[0 0 0 0 0]
[2.2 3.8]
[Ali Veli ]
[Ali Veli Ahmet] - type: [3]string
  • Dizilerin elemanlarını iterate etmek istersek
    range
    kullanabiliriz.
1nums := [5]int{1, 2, 3, 4, 5}
2
3for _, num := range nums {
4  fmt.Print(num)
5}
12345
  • String değerleri iterate ederken de
    range
    kullanabiliriz. Ancak öğeyi değil, byte değerini döner. Dolayısıyla stringe çevirmemiz gerekir.
1var mySentence = "Sentence"
2
3for index, letter := range mySentence {
4	fmt.Println("Index:", index, "Byte:", letter, "Letter:", string(letter))
5}
Index: 0 Byte: 83  Letter: S
Index: 1 Byte: 101 Letter: e
Index: 2 Byte: 110 Letter: n
Index: 3 Byte: 116 Letter: t
Index: 4 Byte: 101 Letter: e
Index: 5 Byte: 110 Letter: n
Index: 6 Byte: 99  Letter: c
Index: 7 Byte: 101 Letter: e
  • Dinamik boyutlu array'ler de tanımlanabilir.
    make(type, len, cap)
    ifadesi
    slice
    ,
    map
    ya da
    channel
    türünden nesne oluşturmak için kullanılır.

var mySlice []int
ifadesini kullanırsak yani ilk değerini vermezsek hataya sebep olur. Çünkü bellekte ayıracağı boyutu bilemez.

1// ilk parametre: eleman türü
2// ikinci parametre: başlangıç boyutu
3// üçüncü parametre: maksimum kapasite
4var mySlice []int = make([]int, 5, 10)
5
6fmt.Println(len(mySlice))
7fmt.Println(cap(mySlice))
5
10
  • Diziyi bölmek istersek iki nokta sözdizimi kullanırız.
1nums := [5]int{1, 2, 3, 4, 5}
2someNums := nums[2:4]
3fmt.Println(reflect.TypeOf(someNums))
4fmt.Println(someNums)
[]int
[3, 4]
  • Dinamik diziye eleman eklemek için built-in
    append()
    metodunu kullanırız. Ekleme yapılacak diziyi ve elemanları alır.
1var arr []int = make([]int, 3, 10)
2newArr := append(arr, 5, 2, 7, 12)
3
4fmt.Println(newArr)
[0 0 0 5 2 7 12]

Map

  • JavaScript'ten bildiğimiz obje gibi anahtar değer çifti tutan veri tipidir. Üç farklı şekilde tanımlayabiliriz.
1// birinci yol
2userInfo1 := map[string]string{
3  "name": "Cem",
4  "surname": "Yılmaz",
5}
6fmt.Println(userInfo1)
7
8// ikinci yol
9userInfo2 := map[string]string{}
10userInfo2["name"] = "Cem"
11userInfo2["surname"] = "Yılmaz"
12fmt.Println(userInfo2)
13
14// üçüncü yol
15var userInfo3 map[string]string = make(map[string]string)
16userInfo3["name"] = "Cem"
17userInfo3["surname"] = "Yılmaz"
18fmt.Println(userInfo3)
map[name:Cem surname:Yılmaz]
map[name:Cem surname:Yılmaz]
map[name:Cem surname:Yılmaz]
  • Golang'de fonksiyonlar ve objeler genellikle iki değer döndürür. İkinci değer, işlemin başarılı olup olmadığını belirtir ve objede bir key olup olmadığını kontrol etmek için de kullanılabilir.
1userInfo := map[string]string{
2  "name":    "Cem",
3  "surname": "Yılmaz",
4}
5
6city, hasCityKey := userInfo["city"]
7fmt.Println("value:", city)
8fmt.Println("hasCityKey:", hasCityKey)
9
10// yalnızca anahtar mevcut olduğunda bir işlem yapmak istersek
11userInfo["city"] = "Istanbul"
12if city, hasCityKey := userInfo["city"]; hasCityKey {
13  fmt.Printf("%s live in %s", userInfo["name"], city)
14}
value:
hasCityKey: false
Cem live in Istanbul
  • Herhangi bir anahtarı silmek istersek
    delete()
    kullanabiliriz.
1userInfo := map[string]string{
2  "name":    "Cem",
3  "surname": "Yılmaz",
4}
5
6delete(userInfo, "surname")
7fmt.Println(userInfo)
map[name:Cem]

Package

  • Built-in paketlerin yanında kendi paketimizi de oluşturabiliriz.
1package utils
2
3func Add(nums ...int) int  {
4  total := 0
5
6  for _, num := range nums {
7    total += num
8  }
9
10  return total
11}
1package main
2
3import (
4  "fmt"
5  "{workspaceFolderName}/utils"
6)
7
8func main()  {
9  utils.Add(2, 21)
10}

math "{workspaceFolderName}/utils"
sözdizimi ile importa isim verebiliriz. Aksi halde paketin ismiyle erişilebilir.

Unit Testing

  • Dosyaların testleri aynı dizinde ve ilgili dosya isminin sonuna
    _test
    eklenmiş şekilde olmalıdır.
1package utils
2
3func Average(nums ...int) int {
4  total := 0
5
6	for _, num := range nums {
7    total += num
8	}
9
10	return total
11}
1package utils
2
3import (
4	"testing"
5)
6
7func TestAverage(t *testing.T) {
8  expected := 4
9  actual := Average(3, 2)
10
11  if actual != expected {
12    t.Errorf(
13      "Add function does not add up: Expected: %d, Actual: %d",
14      expected,
15      actual
16    )
17  }
18}

Resources