github icontwitter icon

Kıssadan Golang [Yaşayan Yazı]

Author imageEnes Başpınar /11 Eki 2022
12 min read •––– views
Warning icon

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

Golang Nedir?

Golang, C gibi ama daha basit, hızlıca derlenebilen, multithread bir dildir. Daha çok mikroservis uygulamalarında kullanılır.

Temel Dosya İçeriği

  • Basit bir Golang dosyasının yapısı (kodu çalıştırmak için go run main.go):

_12
// kod organizasyonu paketler ile sağlanır.
_12
// aynı klasör içinde bulunan dosyalarda paket ismi aynı olmalıdır.
_12
package main
_12
_12
// kütüphaneler klasik şekilde dahil edilir.
_12
import "fmt"
_12
_12
// programın giriş noktasıdır.
_12
// her pakette bir main fonksiyonu olabilir.
_12
func main() {
_12
fmt.Println("Hello World")
_12
}

Yazdırma Biçimleri

  • Farklı yazdırma fonksiyonlarına sahiptir. Print ile başlayanlar stdout'a yani konsola çıktı verir. Fprint olanlar dosya ve tarayıcı gibi dış bir kaynağa, Sprint olanlar ise çıktıyı character buffer'da saklar.

_13
package main
_13
_13
import "fmt"
_13
_13
func main(){
_13
// Printler metnin byte sayısını döndürür.
_13
fmt.Println("Hello!")
_13
fmt.Print("Hello!\n")
_13
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)
_13
_13
// "Hello Enes!" metni döndürür ama çıktı vermez.
_13
result := fmt.Sprintf("Hello %s!", "Enes")
_13
}

Tipler

  • 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 değerin tipini görmek istersek reflect.TypeOf() kullanabiliriz.

_1
fmt.Println(reflect.TypeOf("Enes")) // => string

  • Tür adlarıyla aynı fonksiyonları convert için kullanabiliriz.

Değişkenler

  • Değişken farklı çeşitlerde tanımlanır.

_9
var text string = "Text"
_9
var text2 = "Text2" // tip için çıkarım (inference) yapabilir.
_9
var text3 string // type vermek zorundayız.
_9
text3 = "Text3"
_9
var text4, text5 = "Text4", "Text5"
_9
_9
// var keywordüne gerek kalmadan değişkeni tanımlar
_9
// ve tipini çıkarır. fonksiyon dışında kullanılamaz.
_9
text6 := "Text6" // eğer değer olmasaydı nil atanırdı.

Koşul Yapıları

  • if-else yapısı parantezsizdir.

_7
if num > 50 {
_7
// ...
_7
} else if num > 20 {
_7
// ...
_7
} else {
_7
// ...
_7
}

  • Eğer bir fonksiyonun değerine göre işlem yapcaksak farklı bir sözdizimi daha mevcut.

_4
// err değişkeni sadece bu blok içinden erişilebilir.
_4
if err := someFunction(); err != nil {
_4
fmt.Println(err.Error())
_4
}

  • switch yapısının iki kullanımı vardır. Değişkenin eşitliğini kontrol edeceksek değişkeni verebiliriz. Aksi takdirde atlayabiliriz. Eğer altındaki case ile ilerletmek istersek fallthrough kullanabiliriz.

_23
var variable string
_23
_23
switch variable {
_23
case "...":
_23
// ...
_23
case "...":
_23
// ...
_23
default:
_23
// ...
_23
}
_23
_23
//=================
_23
_23
var num string
_23
_23
switch {
_23
case num < 50:
_23
// ...
_23
case num < 100:
_23
// ...
_23
default:
_23
// ...
_23
}

  • for yapısının da farklı kullanımları mevcut. while için ayrı bir yapı söz konusu değildir.

_10
for i := 1; i <= 100; i++ {
_10
fmt.Println(i)
_10
}
_10
_10
i := 0
_10
for i <= 100 {
_10
fmt.Println(i)
_10
// This will behave like a while loop
_10
i += 1
_10
}

Fonksiyon

  • Fonksiyonda tipleri verirken TypeScript'ten farklı olarak iki nokta kullanmayız.

_14
package main
_14
_14
import (
_14
"fmt"
_14
"time"
_14
)
_14
_14
func main() {
_14
fmt.Println(getAgeByYear(1999))
_14
}
_14
_14
func getAgeByYear(yearOfBirth int) int {
_14
return time.Now().Year() - yearOfBirth
_14
}

  • Birden fazla değer döndürebiliriz.

_3
func blaBla() (int, int) {
_3
return 4, 5
_3
}

  • Ve hatta döndüreceğimiz değerleri otomatik değişkene atayıp dönmesini sağlayabiliriz.

_4
func getAgeByYear(yearOfBirth int) (age int) {
_4
age = time.Now().Year() - yearOfBirth
_4
return
_4
}

  • Belirsiz sayıda argümanı koleksiyon olarak almak istersek ... operatörünü kullanabiliriz. Bu fonksiyonlara variadic function denir.

_27
func printNames(names ...string) {
_27
for _, name := range names {
_27
fmt.Println(name)
_27
}
_27
}
_27
 ```
_27
_27
## Array
_27
_27
* Dizi tanımlarken boyutu sabit, elemanları ise tek tip olmalıdır.
_27
Dikkat etmek gereken şey tip tanımının içerisinde bulunmasıdır. Yani
_27
`[5]int != [4]int`. Eğer girdiğimiz eleman kadar boyut alsın istersek
_27
yine `...` operatörünü kullanabiliriz.
_27
_27
```go
_27
var nums [5]int
_27
fmt.Println(nums)
_27
_27
var nums2 [2]float64 = [2]float64{2.2, 3.8}
_27
fmt.Println(nums2)
_27
_27
names := [4]string{"Ali", "Veli"}
_27
fmt.Println(names)
_27
_27
names2 := [...]string{"Ali", "Veli", "Ahmet"}
_27
fmt.Print(names2)
_27
fmt.Println(" - type: ", reflect.TypeOf(names2))

=== Output:

[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.

_6
nums := [5]int{1, 2, 3, 4, 5}
_6
_6
// indexi göz ardı edeceksek '_' kullanabiliriz.
_6
for _, num := range nums {
_6
fmt.Print(num)
_6
}

=== Output:

12345


_6
var mySentence = "Sentence"
_6
_6
for index, letter := range mySentence {
_6
// letter byte değerini döner. harfi almak için stringe çeviririz.
_6
fmt.Println("Index:", index, "Letter:", string(letter))
_6
}

=== Output:

Index: 0 Letter: S Index: 1 Letter: e Index: 2 Letter: n Index: 3 Letter: t Index: 4 Letter: e Index: 5 Letter: n Index: 6 Letter: c Index: 7 Letter: e

  • Sabit boyut demişken dinamik tanımı da bilmek isteriz. map(type, len, cap), slice, map ve channel türünden nesne oluşturur ve bellekte yer ayırır.

_7
// var mySlice []int dersek bu hataya sebep olur. çünkü bellekte
_7
// ayıracağı boyutu bilemez. map ilk eleman dizinin tipidir.
_7
// ikincisi başlangıç boyutudur. üçüncüsü ise maksimum kapasitedir.
_7
var mySlice []int = make([]int, 5, 10)
_7
_7
fmt.Println(len(mySlice))
_7
fmt.Println(cap(mySlice))

  • Dizinin bir parçasını almak istersek klasik dizi söz dizimini kullanabiliriz.

_4
nums := [5]int{1, 2, 3, 4, 5}
_4
someNums := nums[2:4] // bellekte kapasitesi 5 olacak şekilde yer ayırır.
_4
fmt.Println(reflect.TypeOf(someNums))
_4
fmt.Println(someNums)

=== Output:

[]int [3, 4]

  • Dinamik diziye eleman eklemek için append() kullanırız. Ekleme yapılacak diziyi ve elemanları alır.

_4
var arr []int = make([]int, 3, 10)
_4
newArr := append(arr, 5, 2, 7, 12)
_4
_4
fmt.Println(newArr)

=== Output:

[0 0 0 5 2 7 12]

Map

  • Bildiğimiz anahtar değer çifti tutan veri tipi.

_13
// var userInfo map[string]string şeklinde tanımlarsak
_13
// başlangıç için bellek ayırma yapamaz.
_13
// slice'dan farklı olarak başlangıç boyutu vermeye gerek yok.
_13
var userInfo map[string]string = make(map[string]string)
_13
userInfo["name"] = "Enes"
_13
userInfo["surname"] = "Başpınar"
_13
fmt.Println(userInfo)
_13
_13
userInfo2 := map[string]string{
_13
"name": "Cem",
_13
"surname": "Yılmaz",
_13
}
_13
fmt.Println(userInfo2)

=== Output:

map[name:Enes surname:Başpınar] map[name:Cem surname:Yılmaz]

  • Bir anahtarın olup olmadığını kontrol etmek istersek exception fırlatmayacağı için farklı bir yol kullanmamız gerekir. Döndürdüğü ikinci değer işlemin başarılı olup olmadığını belirtir.

_14
userInfo := map[string]string{
_14
"name": "Cem",
_14
"surname": "Yılmaz",
_14
}
_14
_14
city, ok := userInfo["city"]
_14
fmt.Println("value:", city)
_14
fmt.Println("ok", ok)
_14
_14
// yukarıdaki case'i if ile birleştirip
_14
// bir anahtar mevcutsa bir işlem yapmak istersek:
_14
if city, ok := userInfo["city"]; ok {
_14
fmt.Printf("%s live in %s", userInfo["name"], city)
_14
}

=== Output:

value: ok false

  • Herhangi bir anahtarı silmek istersek delete() kullanabiliriz.

_8
userInfo := map[string]string{
_8
"name": "Cem",
_8
"surname": "Yılmaz",
_8
}
_8
_8
delete(userInfo, "surname")
_8
_8
fmt.Println(userInfo)

=== Output:

map[name:Cem]

Paket

  • Kendi paketimizi de oluşturabiliriz.

_11
package utils
_11
_11
func Add(nums ...int) int {
_11
total := 0
_11
_11
for _, num := range nums {
_11
total += num
_11
}
_11
_11
return total
_11
}


_11
package main
_11
_11
import (
_11
"fmt"
_11
"project-folder/utils"
_11
// math "{workspaceFolderName}/utils" : importa isim verebiliriz
_11
)
_11
_11
func main() {
_11
utils.Add()
_11
}

Unit Testing

  • Test dosyasının ismi test edilen dosyanın sonuna _test eklenmiş halidir. Bu iki dosya aynı dizinde olmalıdır.

_13
package utils
_13
_13
import (
_13
"testing"
_13
)
_13
_13
func TestAverage(t *testing.T) {
_13
expected := 4
_13
actual := Average(3, 2)
_13
_13
if actual != expected {
_13
t.Errorf("Add function does not add up: Expected: %d, Actual: %d", expected, actual)
_13
}


_11
package utils
_11
_11
func Average(nums ...int) int {
_11
total := 0
_11
_11
for _, num := range nums {
_11
total += num
_11
}
_11
_11
return total
_11
}

Diğer

  • Paketlerin dökümantasyonlarını görmek için go doc fmt yazabiliriz. Özel fonksiyon dökümantasyonu için go doc fmt.Println.

_10
func Fprint(w io.Writer, a ...any) (n int, err error)
_10
func Fprintf(w io.Writer, format string, a ...any) (n int, err error)
_10
func Fprintln(w io.Writer, a ...any) (n int, err error)
_10
func Print(a ...any) (n int, err error)
_10
func Printf(format string, a ...any) (n int, err error)
_10
func Println(a ...any) (n int, err error)
_10
func Sprint(a ...any) string
_10
func Sprintf(format string, a ...any) string
_10
func Sprintln(a ...any) string
_10
...

Kaynaklar

2022 © No rights are reserved.Inspired by Lee Robinson's blog.