Avatar Ben Süleyman ERGEN. Siber güvenlik ile uğraşmayı seviyorum. Bol bol ctf çözer ve write-up yazarım. Burada ise edindiğim tecrübeleri ve bilgileri paylaşıyorum.

GO NOTLARIM

GO NOTLARIM

Hello World

Geleneksel hello world programı

// tek satırlık yorum satırı.

/*
çok satırlık yorum satırları.
*/

// programın ana paketi
package main

// fmt paketini import ediyoruz
import "fmt"

// main programı. Program buradan çalışmaya başlar.
func main() {
    // ekrana "hello world" yazdırır.
    fmt.Println("hello world")
}

Terminalden programımızı çalıştıralım.

$ go run hello-world.go
hello world

$ go build hello-world.go
$ ls
hello-world hello-world.go

$ ./hello-world
hello world
  • go run programı derler ve çalıştırır. Fakat derlenmiş dosyayı kaydetmez.
  • bo build programı derler ve derlenmiş dosyayı kaydeder.

Paketler

Her go programı paketlerden oluşur. Programlar main paketinden çalışmay başlar. Ayrıca go biçok pakete sahiptir. Bu paketleri import ile programımıza dahil edebiliriz.

// paketleri ayrı ayrı dahil et
import "fmt"
import "math"

// paketleri tek import ile programa dahil et.
import (
    "fmt"
    "math"
)

Aynı şekilde paketlerdeki isimleri içe aktardığımız gibi dışa katarmakta vardır. Dışa aktaracağımız isimlerin ilk harfini büyük harfle başlaması gerekir. örneğin math.Pi de olduğu gibi.

Değişkenler ve Değerler

var anahtar kelimesi değişken tanımlamaya yarar. Tür bilgisi değişkenin sonuna yazılır.

// tek değişken tanımlanırken.
var a int

// aynı türde çok değişken tanımlanırken
var c, python, java int

// değişkenleri ilklendirme
var i, j int = 1, 2
var x, y = 2, 4

// değişkende ilklendirme varsa o zaman tip belirtimi atlanabilir.
// Bu durumda değişkenin türü ilklendirme türü ile aynı olacaktır
x := 3
// Dikkat!!! fonksiyon alanı dışında kullanılamaz.
// main de bir fonksiyon alanıdır.

// birden çok değişkeni tanımlamanın başka bir yolu
var (
    ToBe   bool   = false
    MaxInt uint64 = 1<<64 - 1
)

Değişlen Türleri

Go çesitli veri tiplerine sahiptir. Go dili statik bir dildir. Yani değişkenin tipi sabittir değiştirilemez.

bool

string

int  int8  int16  int32  int64
uint uint8 uint16 uint32 uint64 uintptr

byte // diğer adıyla uint8

rune // diğer adıyla int32
     // Unicode karakter kodlarını ifade eder

float32 float64

complex64 complex128
  • int* türleri işaretli sayılardır. -2 2 -4 6 gibi.
  • uint* tipleri ise işaretsiz yani pozitif sayılardır. 0 1 2 5 gibi.
  • int uint uintptr platform bağımlı tiplerdir. Makinenin çalıştığı platforma göre değişir.
  • NaN Not a number.( 0/0 durumlarında). (sonsuzluk durumlarında).

Ayrıca bu değişkenlerin kendilerine ait “sıfır değerleri” vardır. Bu değerler şunlardır:

  • 0 Sayı türleri için.
  • false mantıksal (boolean) türü için.
  • "" string türü için.

Tür Dönüşümleri

T(v) ifadesi v değerini T türüne dönüştürür.

var i int = 42
var f float64 = float64(i)
var u uint = uint(f)

Sabitler

Sabitler const ile tanımlanır.

const Pi float64 = 3.14
const Pi = 3.14

// birden fazla sabit tanımlama
const (
    Big = 1 << 100
    Small = Big >> 99
)

Koşul İfadeleri (if else switch)

Go da if deyiminde parantez ( ) kullanılmaz ve süslü parantezler { } zorunludur.

if i < 10{
    // ...
}

if de koşuldan önce çalıştırılacak kısa bir deyim bulunabilir. Bu değişken sadece if koşulu içinde ve else içinde tanımlıdır.

i := 14
if x := 3; i < 10 {
    fmt.Println(x, " ", i)
} else if 10 <= i && i < 20 {
    fmt.Println(x, " ", i)
} else {
    fmt.Println(x, " ", i)
}

Go da switch yapısı şu şekildedir.

switch os := runtime.GOOS; os {
case "darwin":
    fmt.Println("OS X.")
case "linux":
    fmt.Println("Linux.")
default:
    fmt.Printf("%s.", os)
}

switch işlenirken case lerden biri doğrulandığında geri kalan switch ifadesi atlanır.

Eğer switch yapısında koşul belirtilmez ise bu ifade switch true ile eşdeğerdir. Bu uzun if-then-else ifadelerine göre daha temizdir.

t := time.Now()
switch {
case t.Hour() < 12:
    fmt.Println("Good morning!")
case t.Hour() < 17:
    fmt.Println("Good afternoon.")
default:
    fmt.Println("Good evening.")
}

Döngüler

Go dilinde sadece for döngüsü vardır. for döngüsü noktalı virgüller ayrılmış üç kısımdan oluşur:

  • ilklendirme deyimi: ilk döngüden önce çalıştırılır. Genellikle sadece döngü içinde geçerli olacak değerler tanımlanır.
  • koşul ifadesi: her döngüden önce değerlendirilir.
  • sonlandırma deyimi: her döngünün sonunda çalıştırılır.

Go dilinde döngü koşulunda parantez ( ) kullanılmaz ve döngünün gövdesi süslü parantezler { } ile belirtilmek zorundadır.

// örek bir for döngüsü
for i := 0; i < 10; i++ {
    fmt.Println(i)
}

// birinci ve üçüncü kısımlar boş kalabilir.
sum := 1
for ; sum < 1000; {
    sum += sum
}

Go da for döngüsündeki noktalı virgülleri atabiliriz. Bu da diğer dillerdeki while döngüsüne eşdeğerdir.

sum := 1
for sum < 1000 {
    sum += sum
}

Eğer döngü koşulu belirtilmez ise sonsuz döngü oluşacaktır.

for {

}

Fonksiyonlar

Fonksiyonlar bir yığında sıralı duran çağrılar gibidir: call stack

  • Her fonksiyon çağırdığımız zaman stack’e push yapıyoruz.
  • Her return yaptığımızda da stack’ten pop ediyoruz.

Defer

İşaretçiler, Diziler ve Dilimler

İşaretçiler (pointers)

Go dilinde pointer vardır ve değişkenin bellekte saklandığı adresi turar. 0 değeri nil dir.

var p *int

& operatörü başına geldiği değerin göstericisini oluşturur. * ise göstericinin gösterdiği değişkenin değerini turar. Buna dolaylı yoldan erişim denir.

i := 42 // i 42 değerini alır.
p = &i // & operatörü i nin göstericisini oluşturur.
fmt.Println(*p) // gösterici üzerinden i nin değerini oku
*p = 21 // gösterici üzerinden i nin değerini

Diziler (array)

Diziler aynı türde eleman tutan değişkenlerdir ve sabit uzunluktadırlar.

// array tanımlaması
var a [5]int
b := [5]int{1, 2, 3, 4, 5}
var twoD [2][3]int

// herhangi bir elemanına ulaşma veya değiştirme
a[4] = 100

Dilimler (slices)

Dizilerin dinamik boyutlu ve esnek yansımasıdır. Eleman barındırmazlar, sadece arka plandaki dizinin bir kısmını nitelerler. Bu nedenle bir dilimin bir elemanının değeri değiştiğinde arka plandaki dizinin elemanıda değişir. Bu değişim aynı diziyi kullanan diğer dilimlerdede görülür.

var a [10]int

// a dizisinin ilk 5 elemanına ait dilim
a[0:5]

// diziyi tamamen dilimleyen ifadeler.
a[0:10]
a[:10]
a[0:]
a[:]
// burada 1. kısım dahil, 2. kısım değildir.

Bir dilimin 2 özelliği vardır:

  • Uzunluk: dilimdeki eleman sayısıdır. len() fonksiyonu ile öğrenilir.
  • Kapasite: cap() fonksiyonu ile öğrenilir.

Boş bir dilim nil değerini alır, uzunluk ve kapasitesi de 0 dır.

Dilimler ayrıca make() fonksiyonu ile oluşturulabilir.

a := make([]int, 5)  // len(a)=5

// append fonksiyonu ile eleman eklenebilir.
a = append(a, 2)

Dilimler range deyimi ile döngülerde şu şekilde kullanılabilirler.

var pow = []int{1, 2, 4, 8, 16, 32, 64, 128}
for i, v := range pow {
    fmt.Printf("2**%d = %d\n", i, v)
}
// 2**0 = 1
// 2**1 = 2
// 2**2 = 4
. . .

for i := range pow {
} // sadece indisi kullanmak istediğinde.

Bir dilim üzerinde dolaşılırken her seferinde iki değer dönülür. İlki indis, ikincisi o indisli elemanın bir kopyası.

Yapılar (struct)

Struct alanlardan oluşan veri topluluğudur. type anahtar kelimesi ile tanımlanır.

type Vertex struct {
    X int
    Y int
}

//bir tane vertex oluştur ve başlangıç değerlerini ver
v := Vertex{1, 2}

v.X = 4
v.Y = 12

fmt.Println(v.X) // 4
fmt.Println(v.Y) // 12

Map ler

Bir map anahtarları değerlere eşler. Bir map in sıfır değeri nil dir. nil eşlemde anahtar bulunmaz. Ayrıca anahtarda oluşturulamaz.

m = make(map[string]Vertex) // map oluştur.
m["Bell Labs"] = Vertex{ // map'a değer ata.
    40.68433, -74.39967,
}

m[key] = elem // map'a eleman ekle
elem = m[key] // map in elemanına ulaş
delete(m, key) // map tan eleman sil

elem, ok := m[key] // bu atama ile ok değişkeni elemanın var olup olmadığına göre değer alır.
// var ise true, yok ise false
//eğer yok ise elem değişkeni türüne göre 0 değerini alır.
var m = map[string]Vertex{
    "Bell Labs": Vertex{
        40.68433, -74.39967,
    },
    "Google": Vertex{
        37.42202, -122.08408,
    },
}

var m = map[string]Vertex{
    "Bell Labs": {40.68433, -74.39967},
    "Google":    {37.42202, -122.08408},
}

Metodlar

Go dilinde sınıf yapısı bulunmaz. Buna karşın türler üzerinde foksiyonlar tanımlanabilir.

type Vertex struct {
    X, Y float64
}

// vertex için fonksiyon tanımladık.
func (v Vertex) Abs() float64 {
    return math.Sqrt(v.X*v.X + v.Y*v.Y)
}

v := Vertex{3, 4}
fmt.Println(v.Abs()) // bu fonksiyonu vertex türü üzerinden çağırdık

all tags