Kısa Kısa Go
- Sentaksı
C
sentaksına yakın - Açık kaynaklı
- Statik tipli
- Programlar native makine koduna derlenir
Imperative
dil- Nesne yönelimli programlama yapılamaz
Object
yok- Dolayısıyla
class
yok Struct
vemethod
varInterface
var- Paket seviyesinde
encapsulation
var - Kalıtım yok (zaten sınıf da yok) ama tip gömme var
- Birinci derece yazılım varlığı fonksiyon
- Fonksiyon, birden fazla değer döndürebilir (aslında bağıntı)
Exception
yokpanic
var- İlave return elemanı olarak
error
döndürme var Closure
varPointer
var ama pointer aritmetiği (unsafe
paketi kullanılmazsa) yok- Temel concurrency elemanları
goroutine
vechannel
- Hızlı derlenir
- Çöp toplayıcısı var
- Dahili paket yöneticisi var
- İşe yaramayan değerler
_
‘ye atanır
2 Temel Ortam Değişkeni
GOROOT
: Go’nun kurulduğu dizini içerir. Bu dizinde derleyici, doküman ve araçlar bulunur
GOPATH
: Üçüncü taraf çalıştırılabilir dosyaların ve üçüncü taraf paketlerin yer aldığı dizini içerir. Bu dizine bir src klasörü içinde kendi geliştirmelerimizi de atabiliriz. go get
üçüncü taraf paketleri bu dizinin içindeki pkg
dizinine indirir
Yorumlar (Comment)
// Tek satır yorum
/*
Çok
satırlı
yorum
*/
Tırnak İşaretlerinin Kullanımı
'A' // Tek tırnak bir tek karakter (mesela char veya rune tiplerinde olan karakter) için kullanılır
"My String" // Birden fazla karakterden oluşan bir string için kullanılır fakat tek satırda tanımlamaya izin verir
`First line
Second line
Third line` // Bir string için kullanılır fakat yeni satır karakterlerinde escape yapmaya ihtiyaç bırakmaz
type MyClass struct {
MyProperty int `json:"my_property,omitempty" xml:"MyProperty"` // Yapılarda meta bilgi annotation amaçlı etiketlemelerde çift tırnak escaping meselesi çıkmaması için kullanılabilir
}
Çalıştırma (Running)
Bir programı en basit şekilde hem derleyip hem de ilk defa çalıştırma:
go run main_iceren_dosya.go
En basit örnek program:
// demo.go
package main
import "fmt"
func main() {
fmt.Println("Merhaba") // -> Merhaba
}
go run demo.go
Derlenmiş programı eğer derlendiği ortam ile özdeş ortamda ise çalıştırma:
./demo
Paketler (Package)
Paket Oluşturma
Her go
dosyası bir pakete dahil edilir. Ve hangi pakete dahil olduğu dosyanın en başında deklare edilir:
package mypack
Çalıştırılabilir dosya (executable) oluşturabilmek için başlangıç noktası (entrypoint) dosyası main
paketine dahil edilir:
package main
Paket Kullanımı
Paketler kullanılması için başka bir dosyaya import
ifadesi aracılığı ile dahil edilir:
import "os"
Birden fazla paket import edilecekse:
import (
"os"
"fmt"
"mymodule/mypack"
"github.com/example/examplepack"
)
Paketlerin sabitleri, değişkenleri, fonksiyonları veya metotlarından yalnızca
exported
olanları paketin dışında kullanılabilir.
Sabit, değişken, fonksiyon ve metotların isimleri büyük harfle başlıyorsa
exported
, küçük harfle başlıyorsaunexported
olur.
Import edilen paketin içinden kullanılacak herhangi varlığın önüne paketin adı eklenip separator
olarak .
kullanılır.
Paketin adı, /
ile ayrılmış paket yolunun son dilimidir.
Paket import edilirken pakete takma ad verilebilir. Mesela mypack
paketi mp
olarak kullanılmak istense:
import (
"fmt"
mp "mymodule/mypack"
)
Import edilen paketin takma adı .
olursa söz konusu kaynak paketteki varlıklar hedef paketin varlığıymış gibi kullanılabilir:
import (
"fmt"
. "mymodule/mypack"
)
Import edilen paketin takma adı _
olursa paket kullanılması için değil içindeki tanımlamalar, deklarasyonlar, başlatmalar gerçekleşsin diye yan etkiler gerçekleşsin diye import edilmiş olur:
import (
_ "example.org/myspace/mypackage"
)
Paket İndirme
Paket indirmek için komut satırından:
go get github.com/example/examplepack
Modüller (Module)
Modül Oluşturma
Komut satırı üzerinden oluşturulacak modülün kök dizinine gelinir ve initialize
edilir:
mkdir mymodule
cd mymodule
go mod init example.com/myspace/mymodule
Bunun sonucunda modülün kök dizininde go.mod
isimli bir dosya oluşur.
Modül içinde modül oluşturulamaz. Bu sebeple modülün kök dizini yolu altında başka bir modülün kök dizini bulunamaz.
Modül Bağımlılıkları
Modülün tüm bağımlılıklarını listelemek için:
go list -m all
Modülü kullanılmayan gereksiz bağımlılıklardan kurtarmak için:
go mod tidy
Modül İndirme
Modül indirme ile paket indirme arasında bir fark yok:
go get example.com/myspace/mymodule
Modül Kullanımı
go build
,go test
gibi paket inşa komutları ile modüle dahil tüm paketlerin bağımlılıklarıgo.mod
dosyasına eklenmiş olur.
Modül ilk defa çalıştırıldığında modül kök dizininde
go.sum
dosyası oluşur. Bu bir bağımlılıklock
dosyasıdır.
Modül İçinde Modül Kullanımı
// go.mod
module example.com/myspace/mymodule
go 1.123
require (
example.com/anotherspace/anothermodule v1.0.0
)
Modül İçinde Yerel Modül Kullanımı
// go.mod
module example.com/myspace/mymodule
go 1.123
replace (
"example.com/myspace/anothermodule" => "../anothermodule"
)
require (
example.com/myspace/anothermodule v1.0.0
)
Operatörler (Operators)
Aritmetik (Arithmetic)
+
topla-
çıkar*
çarp/
böl%
kalanı bul
Bitsel (Bitwise)
&
bitsel “ve”|
bitsel “veya”^
bitsel “ya da”&^
bitsel “ve değil”<<
bitleri sola kaydır>>
bitleri sağa kaydır
Mantıksal (Logical)
!
mantıksal “değil”&&
mantıksal “ve”||
mantıksal “veya”
Karşılaştırma (Comparison)
==
eşit mi?!=
eşit değil mi?<
küçük mü?<=
küçük veya eşit mi?>
büyük mü?>=
büyük veya eşit mi?
Atama (Assignment)
=
ata:=
deklarasyonlu ata / implicit tipli ata+=
ekle ve ata-=
çıkar ve ata*=
çarp ve ata/=
böl ve ata%=
kalanı bul ve ata&=
bitsel “ve” uygula ve ata|=
bitsel “veya” uygula ve ata^=
bitsel “ya da” uygula ve ata<<=
bitleri sola kaydır ve ata>>=
bitleri sağa kaydır ve ata
Kanal (Channel)
<-
gönder / al
İşaretçi (Pointer)
&
pointer oluştur (address operator)*
referansı getir (dereferencing operator) (tabi bunu işaretçi tipi notasyonu için kullanılan * ile karıştırmamak lazım)
Yerleşik Tipler (Built-in Types)
Yerleşik tipler türetilip özel tipler elde edilebilir
Basit Tipler (Basic Types)
bool
// varsayılan değeri falseint
// varsayılan değeri 0int8
// varsayılan değeri 0int16
// varsayılan değeri 0int32
// varsayılan değeri 0rune
// unicode code point, int32 ‘nin diğer adı, varsayılan değeri 0int64
// varsayılan değeri 0uint
// varsayılan değeri 0uint8
// varsayılan değeri 0byte
// uint8 ‘in diğer adı, varsayılan değeri 0uint16
// varsayılan değeri 0uint32
// varsayılan değeri 0uint64
// varsayılan değeri 0uintptr
// varsayılan değeri 0float32
// varsayılan değeri 0float64
// varsayılan değeri 0string
// varsayılan değeri “”complex64
// varsayılan değeri (0+0i)complex128
// varsayılan değeri (0+0i)
Basit tipteki bir değişken boş olamaz. O değişken mutlaka, tipin varsayılan değerine sahiptir.
Karma Tipler (Composite Types)
Yapı Tipleri (Struct Types)
struct
türevi tiplere metot bağlanabilir
Fonksiyon Tipleri (Func Types)
İşaretçi Tipleri (Pointer Types)
Doğrudan bir tipin başına
*
konmasıyla ifade edilir
İşaretçi tiplere metot bağlanabilir
İşaretçi türevi tiplere metot bağlanamaz
Kanal Tipleri (Channel Types)
chan
veya türevi tiplere metot bağlanamaz
Arayüz Tipleri (Interface Types)
interface{}
dinamik tip anlamına geliyor
Konteyner Tipler (Container Types)
- Diziler (Arrays) – Sabit uzunluk (list gibi)
- Dilimler (Slices) – Değişken uzunluk ve değişken kapasite
- Maps – Değişken uzunluk (associative array veya dictionary gibi)
Array, slice veya
map
türevi tiplere metot bağlanabilir
Fonksiyon Çağırma (Function Call)
myFunction() // Değer dönmeyen bir fonksiyonun çağrımı
yourFunction(v) // Değer alan ama değer döndürmeyen bir fonksiyonun çağrımı
i := int(f) // Değer alan ve değer döndüren bir fonksiyonun çağrımı
Diziler (Array)
a := [5]int{1, 2, 4, 8, 16} // Beş elemanlı array oluştu
a[4] = 32 // Array'in beşinci elemanı 32 oldu
n := a[4] // Değişken int olarak tanımlandı ve 32 oldu
a := [...]{2, 4, 6} // Derleyici array'in boyutunu 3 olarak anlar
Dilimler (Slice)
s := []int{1, 2, 3} // Üç elemanlı bir array'in hepsi bir slice olarak alındı
k := []string{0: "a", 2: "c", 1: "b"} // [a b c] şeklinde bir slice
a := [3]string{"a", "b", "c"} // Üç elemanlı array oluştu
s := a[:] // Array'in hepsi slice olarak alındı
a := [4]string{"a", "b", "c", "d"} // Dört elemanlı array oluştu
s1 := a[0:4] // Array'in ilk elemanından dördüncü ve son elemanına kadar dilim olarak alındı
s2 := a[1:] // Array'in ikinci elemanından son elemanına kadar dilim olarak alındı
s3 := a[:3] // Array'in ilk elemanından üçüncü elemanına kadar dilim olarak alındı
low := 1
high := 3
s4 := a[low:high] // Array'in ikinci elemanından üçüncü elemanına kadar dilim olarak alındı
s := []string{"a", "b", "c", "d"} // [a b c d] şeklindeki bir slice
s = append(s, "e", "f", "g") // Slice [a b c d e f g] şeklini aldı
s1 := []string{"a", "b", "c", "d"} // [a b c d] şeklinde bir slice
s2 := []string{"e", "f", "g", "h"} // [e f g h] şeklinde bir slice
s3 := append(s1, s2...) // -> [a b c d e f g h] şeklinde türemiş bir slice
s1 := make([]int, 3) // Üç elemanlı bir array'den [0 0 0] şeklinde bir slice, kapasite opsiyonel
l1 := len(s1) // Uzunluk 3
c1 := cap(s1) // Kapasite 3
s2 := make([]int, 3, 10) // On elemanlı bir array'den [0 0 0] şeklinde bir slice
l2 := len(s2) // Uzunluk 3
c2 := cap(s2) // Kapasite 10
Map
m := map[string]bool{"k1": true, "k2": false} // map[k1:true k2:false] şeklinde bir map oluştu
m["k2"] = true // k2 anahtarlı eleman true oldu
e, ok := m["k2"] // k2 anahtarlı eleman mevcut olduğundan e -> true ve ok -> true
e, ok := m["k3"] // k3 anahtarlı eleman mevcut olmadığından e -> false (varsayılan bool değeri) ve ok -> false
m := make(map[string]int) // Boş bir string anahtarlı int map'i
m["key"] = 12 // key anahtarlı 12 değeri set edildi
delete(m, "key") // key anahtarlı değer unset edildi
Yapılar (Struct)
Yapı Deklarasyonu (Struct Declaration)
type Abc struct {
A, B, C int
}
type Ghi struct {
G string
H int; I float64
}
Yapı Örnekleme (Struct Instantiating)
abc1 := Abc{1, 2, 3} // {1 2 3} şeklinde
abc2 := Abc{A: 1, C: 3} // {1 0 3} şeklinde
col := []Abc{ {1, 2, 3}, {4, 5, 6} } // [{1 2 3} {4 5 6}] şeklinde
Struct Üyelerine / Alanlara Erişim (Accessing Struct Members / Fields)
type Abc struct {
A, B, C int
}
abc := Abc{1, 2, 3} // {1 2 3} şeklinde
abc.A = 4 // {4 2 3} şeklinde
abc.C = 6 // {4 2 6} şeklinde
b := abc.B // b -> 2
struct member
=field
Arayüzler (Interface)
Arayüz Deklarasyonu (Interface Declaration)
type Producer interface {
Produce() float64
Consume()
}
Somut tiplerin hangi
interface
‘i gerçekleyeceği deklare edilmez.
Dinamik Tip (Dynamic Types)
…
Değişken Deklarasyonu (Variable Declaration)
var i int // Tek değişken deklare edildi ama initialize edilmedi. Değişkenin değeri int tipinin varsayılan değeri olan 0
var j int = 123 // Tek değişken hem deklare hem de initialize edildi
var k1, k2 int // Birden fazla değişken tek seferde deklare edildi ama initialize edilmedi
var l1, l2 int = 123, 456 // Birden fazla değişken tek seferde hem deklare hem de initialize edildi
n := 789 // Implicit tipli değişken deklarasyonu, yalnızca fonksiyon gövdelerinde, tip kararı derleyicide
Tip İddiaları (Type Assertion)
var i interface{} = "mystring" // i değişkeni aslında bir string
var v int // v değişkenini int olarak varsay
var ok bool
v, ok = i.(int) // i değişkeninin int olduğunu iddia ederek v değişkenine ata
fmt.Println(v, ok) // v değişkeninin değeri 0 olur, çünkü i aslında bir string, int olduğu yalnızca bir iddia idi, yani tip dönüştürmesi söz konusu değil, haliyle isabet değişkeni olan ok değişkeni de false olur
var i interface{} = true // i aslında bir bool
var v string // v değişkenini string olarak varsay
v = i.(string) // i değişkeninin string olduğunu iddia ederek v değişkenine atarken isabet değişkenini eksik bırakırsan "panic" alırsın
var i interface{} = 1.0
v, ok := i.(string) // şeklinde veya
y, _ := i.(bool) // şeklinde de iddia edilebilir
Anonim Yapılar (Anonymous Struct)
myStruct := struct {
A, B int
}{1, 2}
Anonim struct kullanımı
map[string]interface{}
kullanımından daha masrafsızdır.
İşaretçiler (Pointers)
// & operatörü bir değişkene veya üyeye işaret eden bir işaretçi oluşturur
abc := Abc{1, 2} // abc, normal bir değişken
p := &abc // p, referansı kapsama alınan bir değişkene işaret eden bir işaretçi
r := &Abc{1, 2} // r, referansı kapsamda bulunmayan bir değişkene işaret eden bir işaretçi
// Başına * getirilmiş doğrudan tip, işaretçi tipidir
p := &Abc{1, 2} // p 'nin tipi *Abc 'dir
var s *Abc = new(Abc) // Yerleşik fonksiyonlardan new fonksiyonu bir Abc 'ye işaret eden bir *Abc tipli işaretçi üretiyor
// * operatörü bir expression 'da bir işaretçinin adının başına getirilirse işaret edilen değişkenin kendisi kastedilmiş olur
var i int
p := &i
fmt.Printf("%v %T\n", p, p) // 0xc000123000 *int
fmt.Printf("%v %T\n", *p, *p) // 0 int
// Dolaylı atama (indirect assignment) yapmak için atama yapılan işaretçinin adının başına * getirilir
var i int = 1
var p *int = &i
*p = 2
fmt.Printf("%v\n", i) // i değişkeninin değeri artık 2
i := 1
p := &i // i 'ye işaret eden bir işaretçi
q := &*p // i 'ye işaret eden bir başka işaretçi
r := *&p // i 'ye işaret eden bir diğer işaretçi
s := []string{"A", "B"} // [A B] []string
p := &s // &[A B] *[]string
a := (*p)[1] // B string
s := "A" // A string
p := &s // 0xA0000012345 *string
q := &p // 0xA0000067890 **string
*(*q) = "B" // s şimdi "B" oldu
**q = "C" // s şimdi "C" oldu
Değişken Kapsamı (Scope of Variables)
Yerel Değişkenler (Local Variables) ve Genel Değişkenler (Global Variables) Farkı
package main
import (
"fmt"
)
var myVariable int = 1 // Herhangi bir blokun dışında olduğu için global değişkendir
func main() { // Fonksiyon tanımı bir bloktur
fmt.Println(myVariable) // Bu noktada myVariable değeri 1, çünkü global değişken geçerli
var myVariable int = 2 // Blokta tanımlandığı için yerel değişkendir. Bu blok ve alt blokların tümünde geçerli. Global olan ile aynı isimde olduğu için de artık bu blok ve alt blokların hiçbirinde global olana erişilemez
fmt.Println(myVariable) // Bu noktada myVariable değeri artık 2
for { // Loop bir bloktur
fmt.Println(myVariable) // Yeni bir bloka daha girildi ama myVariable değeri hala 2
var myVariable int = 3 // Blokta tanımlandığı için yine yerel değişkendir. Bu blok ve alt blokların tümünde geçerli. Üst blokta yani fonksiyon blokunda tanımlanan ile aynı isimde olduğu için üst bloktakine de globaldekine de erişilemez
fmt.Println(myVariable) // Bu noktada myVariable değeri artık 3
break
}
fmt.Println(myVariable) // Loop blokundan çıkıldığı için bu noktada myVariable değeri 2
}
Sabit Deklarasyonu (Constant Declaration)
const c1 int = 123 // Tip belirleyerek sabit deklarasyonu
const c2 = 456 // Implicit tipli sabit deklarasyonu
Yapı Gömme (Struct Embedding)
type Client struct {
ApiHost string
ApiPort int
*log.Logger
}
client := &Client{"api.example.com", 80, log.New()}
client.Log("Ok") // Logger gömüldüğünden dolayı bu şekilde yazılarak aslında client.Logger.Log() çağrılır
var logger *log.Logger = client.Logger // Bu da sağlaması
Tip Dönüşümleri / Tip Çarpıtma (Type Conversion / Type Casting)
Yerleşik tip dönüşüm fonksiyonlarının adları tiplerin adları ile aynıdır.
f := -123.45 // -123.45
i := int(f) // -123
u := uint(i) // 18446744073709551493
Kontrol Yapıları (Control Structures)
If-Else
// Basit if - else if - else
if i > 0 {
return 1
} else if i == 0 {
return 0
} else {
return -1
}
if i := j * k; i > 0 {
return 1
} else {
return 0
}
Döngüler (Loop)
// Yalnızca for var. while, do - while veya until yok
for i := 0; i < 10; i++ {
}
for ; i < 10; { // while gibi çalışır
}
for i < 10 { // Elde yalnızca şart varsa ; notasyonu yazılmayabilir
}
for { // Şartı sabit true olan while gibi çalışır
}
for i := 0; i < 10; i++ {
continue
}
for {
if i >= 10 {
break
}
i = i + 1
}
Switch
// Basit switch
switch operatingSystem {
case "darwin":
fmt.Println("macOS")
// break ifadesine gerek yok
case "linux":
fmt.Println("Linux")
default:
fmt.Println("Other")
}
// Switch'e konu değişkeni bildirmeden önce değişkene atama yapılabilir
switch os := runtime.GOOS; os {
case "darwin":
fmt.Println("macOS")
case "linux":
fmt.Println("Linux")
default:
fmt.Println("Other")
}
// Karşılaştırma case 'leri mümkün
i := 2
switch i {
case i > 0:
fmt.Println("Positive")
case i < 0:
fmt.Println("Negative")
default:
fmt.Println("Zero")
}
// Case 'e dikkat
var c byte = '-'
switch c {
case '.', '-', '/':
fmt.Println("It is a separator")
// default ifadesi zorunlu değil
}
Range
for ik, e := range array_or_slice_or_map {
// ik -> endeks veya anahtar, e -> eleman
}
for ik := range array_or_slice_or_map { // Yalnız endeks veya anahtar lazım ise...
}
for _, e := range array_or_slice_or_map { // Yalnız eleman lazım ise...
}
for range time.Tick(time.Second) { // Hiçbir değişken lazım olmayabilir de...
}
İterasyonda Elemanı Kaynağından Kullanmak
for idx := range array_or_slice { // Yalnız endeks lazım
element := &array_or_slice[idx]
fmt.Println("%v", element)
}
Kaynağından kullanım tasarruf sağlar
Tikleyici (Ticker)
for range time.Tick(1 * time.Second) { // Saniyede bir döner
fmt.Println("Zıp...")
}
Fonksiyonlar (Function)
Go’da fonksiyonların seçimlik (optional) parametresi olmaz
İsimlendirilmiş Fonksiyon Tanımlama (Named Function Declaration)
func doSomething() { // İsimlendirilmiş argüman yok, döndürülen değer yok
}
func doSomething() string { // İsimlendirilmiş argüman yok, tek değer döndürülür
return "something"
}
func doSomething() (string, error) { // İsimlendirilmiş argüman yok, biri ilkel, diğeri arayüze sahip olan iki isimlendirilmemiş değer döndürülür
return "something", nil // İkinci değer arayüze sahip bir değer olduğundan dolayı nil olabilir
}
func doSomething(someArgument string) { // Tek isimlendirilmiş argüman var, döndürülen değer yok
}
func doSomething(someArgument int, anotherArgument int) { // İki isimlendirilmiş argüman var, döndürülen değer yok
}
func doSomething(someArgument, anotherArgument int) int { // İki isimlendirilmiş aynı tipte argüman var, tek değer döndürülür
return someArgument + anotherArgument
}
func doSomething() (someValue int, anotherValue int) { // İsimlendirilmiş argüman yok, isimlendirilmiş iki değer döndürülür, isimlendirilmiş değerler değişken olarak tanımlanmış olur
return // Çıplak (naked) döndürme..
}
Değer Halindeki Fonksiyonlar (Functions As Values)
var duplicate func(int) int
duplicate = func(i int) int {
return i * 2
}
divideInHalf := func(i int) int {
return i / 2
}
a := duplicate(12) // 24
b := divideInHalf(48) // 24
Closure
func newIncreaser(step int) func() int { // Anonim fonksiyon olarak closure döndüren bir fonksiyon
c := 0 // Global değişkene de gerek yok, dışarıdan enjekte etmeye de gerek yok. Sayaç enkapsüle edilmiş oluyor
return func() int { // Sayaç üzerinde manipülasyon yapacak olan closure
c += step // Bu closure c ve step değişkenlerine bağlı (bound)
return c // Manipüle edilmiş sayacın son halinin kopyası döndürülüyor
}
}
increase := newIncreaser(1) // Anonim fonksiyona, yani closure 'a isim veriliyor
// Her çağrışta dönen değerin arttığı görülecek
fmt.Println(increase()) // 1
fmt.Println(increase()) // 2
fmt.Println(increase()) // 3
Lexical Scope
…
Varyadik Fonksiyonlar (Variadic Functions)
func multiply(integers ...int) int {
return doCalculation(0, integers...)
}
func doCalculation(ctype int, integers ...int) int {
if 0 == ctype {
if 1 < len(integers) {
return integers[0] * doCalculation(0, integers[1:]...)
}
return integers[0]
}
return 0
}
a := multiply(2, 3, 4) // 24
// veya
b := multiply([]int{2, 3, 4}...) // 24
Defer
func doSomething() {
defer fmt.Println("C") // Fonksiyon bittiğinde çalıştır
defer fmt.Println("B") // Fonksiyon bittiğinde çalıştır
fmt.Println("A")
}
doSomething()
// Çıktı şunun gibi olur:
// A
// B
// C
Metotlar (Methods)
Bir metot, aslında alıcı (receiver) argümanı olan bir fonksiyondur.
Alıcı argümanı özel bir argümandır ve yalnızca isimlendirilmiş bir tip paslanır.
Metot Tanımlama (Method Declaration)
Değer Alıcı ile Metot Tanımlama (Method Declaration with Value Receiver)
type MyType struct {
someValue string
}
func (t MyType) DoSomething() { // MyType yapısının bir metodu, t değişkenindeki değer orijinal değer olamaz
fmt.Println(t.someValue)
}
İşaretçi Alıcı ile Metot Tanımlama (Method Declaration with Pointer Receiver)
type MyType struct {
someValue string
}
func (t *MyType) DoSomething() { // MyType yapısının bir metodu, t işaretçisindeki değer orijinaldir, yapılacak değişiklik orijinalde yapılır
t.someValue = "New value" // Metodun çağrıldığı noktada yapının orijinalindeki değer değişmiş olur
fmt.Println(t.someValue)
}
İşaretçi alıcı daima daha tasarrufludur. Çünkü metot alıcısına paslanan değer kopya değildir.
Gizli Arayüz Gerçeklemesi (Implicit Interface Fitting)
Bir tipe bağlanan metotlar bir interface
‘de deklare edilen metotların hepsini gerçekliyorsa o tip o interface
‘i gerçeklemiş demektir:
type Producer interface {
Produce() float64
Consume()
}
type Abc struct {}
func (abc Abc) Produce() float64 {
return 1.2
}
func (abc Abc) Consume() {
fmt.Println("Consumed")
}
// Abc yapısı Producer arayüzünü gerçeklemiş oldu
SomeType
ile*SomeType
farklı tiplerdir. Bu yüzden metotlar tanımlanırken dikkat edilmelidir.
Metot Çağırma (Method Calling)
type SomeType struct {
someProperty int
}
func (t *SomeType) DoSomething() {
}
func (t SomeType) DoAnotherThing() {
}
// Bir tipin metodu, bir yapının üyesine erişiyormuş gibi "." ile bağlanarak çağrılır. Gerisi sıradan bir fonksiyon çağırma ile aynı şeydir
var v SomeType
v.DoSomething() // Bu da çalışır
(&v).DoSomething() // Bu da çalışır
p := &v
p.DoSomething() // Bu da çalışır
var v SomeType
v.DoAnotherThing() // Bu da çalışır
p := &v
(*p).DoAnotherThing() // Bu da çalışır
p.DoAnotherThing() // Bu da çalışır
type Foo interface {
DoSomething()
}
type Bar interface {
DoAnotherThing()
}
type Baz struct {}
func (b *Baz) DoSomething() {
// do something
}
func (b *Baz) DoAnotherThing() {
// do another thing
}
func (b *Baz) DoSpecialThing() {
// do special thing
}
func handle(b Foo) { // i argümanı Foo arayüzüne sahip varsayılıyor
b.DoSomething() // Foo arayüzüne sahip olduğu bilindiği için arayüzün metodu doğrudan çağrılıyor
b.(Bar).DoAnotherThing() // Ama bu noktada aynı zamanda Bar arayüzüne de sahip olduğu bilinmediği için Bar arayüzüne sahip olduğu iddia edilerek Bar arayüzünün metodu çağrılıyor
b.(*Baz).DoSpecialThing() // Arayüz yerine doğrudan yapının kendisi olduğu da iddia edilebilir
}
Hata Ele Alımı (Error Handling)
Fonksiyonlar birden fazla değer döndürebildiğinden dolayı bir fonksiyonun son döndürdüğü değeri hata yapısı olarak belirlemek yeterlidir. Exception eksikliği hissedilmez.
// Ortak kullanım için standart hata arayüzü bu şekilde (built-in) tanımlıdır (predeclared identifier)
type error interface {
Error() string
}
Hata yapısı tanımlanacaksa yapı isminin sonuna
...Error
eklenmesi, hata atanacak bir değişken tanımlanacaksa değişken isminin başınaerr...
veyaErr...
eklenmesi teamüldür ve tavsiye edilir.
// Hem başarı değeri hem standart hata arayüzü gerçekleyen hata değeri döndürebilen bir fonksiyonumuz olsun
func doSomething() (float64, error) {
// ...
}
func main() {
r, err := doSomething()
if nil != err {
// Hata boş değil, o zaman ele al (handle the error)
} else {
// Hata yok, o zaman yoluna devam et
}
}
Panic
Panic Ele Alımı (Panic Recovery)
…
Hata mesajlarının küçük harflerle yazılması ve hata mesajlarının sonuna nokta konulmaması teamüldür ve tavsiye edilir
Eşzamanlılık (Concurrency)
Goroutine’ler (Goroutines)
Goroutine’ler Go tarafından yönetilen (yani işletim sistemi tarafından yönetilmeyen) az masraflı thread’lerdir.
func myRoutine(s string) { // goroutine olarak çağrılacak isimlendirilmiş fonksiyon
// ...
}
func main() {
go myRoutine("blabla") // isimlendirilmiş fonksiyonun goroutine olarak çağrılması
}
func main() {
go func (i int) { // anonim fonksiyonun goroutine olarak başlatılması
// ...
}(12) // i parametresine 12 verilerek başlatıldı
}
Kanallar (Channels)
ch := make(chan int) // Bir integer kanalı oluşturuldu
ch <- 12 // ch kanalına 12 değeri gönderildi
i := <-ch // ch kanalından değer alındı
var c chan string
c <- "Something"
// fatal error: all goroutines are asleep - deadlock!
var c chan string
fmt.Println(<-c)
// fatal error: all goroutines are asleep - deadlock!
var c = make(chan string, 1)
c <- "Something"
close(c)
c <- "Something"
// panic: send on closed channel
var c = make(chan int, 2)
c <- 1
c <- 2
close(c)
fmt.Println(<-c) // 1
fmt.Println(<-c) // 2
fmt.Println(<-c) // 0
fmt.Println(<-c) // 0
Eşzamanlı Çalıştırma Örneği
// Paralel çalıştırılacak fonksiyonların çıktısı olacak yapı
type channelDTO struct {
payload interface{}
error error
}
// Paralel çalışacak bir prosedür içeren fonksiyonlardan biri
func retrieveAbc(ch chan channelDTO, otherParameter bool) {
// do something
ch <- channelDTO{
payload: "OK",
error: nil,
}
}
// Paralel çalışacak bir prosedür içeren fonksiyonlardan diğeri
func retrieveDef(ch chan channelDTO, anotherParameter int) {
// do something
ch <- channelDTO{
payload: "HELLO",
error: nil,
}
}
// Kanallar hazırlanıyor
abcChannel := make(chan channelDTO)
defChannel := make(chan channelDTO)
// Paralel çalıştırma siparişi veriliyor
go retrieveAbc(abcChannel, false)
go retrieveDef(defChannel, 0)
// Paralel çalıştırmaların meyveleri toplanıyor
channelDtoForAbc, channelDtoForDef := <-abcChannel, <-defChannel
Reflection
…
Type Switch
func printType(v interface{}) { // v interface{} demek herhangi bir tipteki v demek
switch t := v.(type) { // v.(type) ifadesi yalnızca switch içinde çalışır
case int:
fmt.Println("Integer")
case float64:
fmt.Println("Float 64")
case string:
fmt.Println("String")
default:
fmt.Println("Other")
}
}
printType(12) // Integer
printType("Hello") // String
printType(1.2) // Float 64
printType(false) // Other
Sinyal Ele Alma (Signal Handling)
package main
import (
"fmt"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
var err error
terminationChannel := make(chan bool)
errorChannel := make(chan error)
fmt.Println("PID:", os.Getpid())
// Bu thread işletim sisteminden, termination 'a sebep olabilecek bir sinyal gelip gelmediğini takip edecek
go handleSignals(terminationChannel)
termination := false
for { // termination true olana kadar tekrarla
// Asıl rutin iş bu thread 'de
go func() {
fmt.Println("...Work...")
time.Sleep(500 * time.Millisecond) // rutin iş güya yarım saniye sürüyor
errorChannel <- nil // Hata yoksa devam... Select bloklaması sona erecek
}()
// Kanallardan birinden cevap bekleme bloklaması
select {
// termination kanalını bir yokla
case termination = <-terminationChannel:
// termination kanalına bir true akmadıysa, hata kanalını bir yokla
case err = <-errorChannel:
if nil != err {
fmt.Println(err.Error())
return
}
// hata yoksa bloklamayı kaldır... Bir bak bakalım termination true mu?
}
if termination {
fmt.Println("It was last cycle. Bye...")
break
}
// termination true ise bir başka rutin başlatılmayacak
}
}
func handleSignals(terminationChannel chan bool) {
var termination bool
var immediate bool
signalChannel := make(chan os.Signal, 1)
// 4 sinyalden biri gelirse sinyal kanalına akıtmak üzre takibe başlar
signal.Notify(signalChannel, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM, syscall.SIGHUP)
for lastSignal := range signalChannel {
fmt.Printf("\nSignal received: %s\n", lastSignal.String())
switch lastSignal {
case syscall.SIGINT, syscall.SIGQUIT:
termination = true
immediate = false
case syscall.SIGTERM:
termination = true
immediate = true
case syscall.SIGHUP:
termination = false
}
if termination {
doJustBeforeTermination()
fmt.Println("Terminating...")
if immediate {
termination = false
os.Exit(0) // Derhal process 'i başarı ile sonlandır
}
}
// report the value of termination via the channel
terminationChannel <- termination
}
}
func doJustBeforeTermination() {
fmt.Println("Doing something just before termination...")
}
Çağrı Yığını Takibi (Tracing Caller Stack)
type CallerFrame struct {
StackIndex int
CallerFilePath string
CallerName string
CallerEntryPointProgramCounter uintptr
CallerEntryPointLine int
CallPointProgramCounter uintptr
CallPointLine int
}
func traceCallerStack(numberOfSkippableFrames int, depth int) []CallerFrame {
callerProgramCounters := make([]uintptr, depth)
n := runtime.Callers(numberOfSkippableFrames, callerProgramCounters)
stack := make([]CallerFrame, 0)
if n > 0 {
var i int
var k int
var callPointProgramCounter uintptr
var callerEntryPointProgramCounter uintptr
var callPointFunc *runtime.Func
var entryPointFunc *runtime.Func
var callerFilePath string
var callPointLine int
var callerEntryPointLine int
for i, k = 0, n; i < n; i++ {
k--
callPointProgramCounter = callerProgramCounters[i]
callPointFunc = runtime.FuncForPC(callPointProgramCounter)
callerEntryPointProgramCounter = callPointFunc.Entry()
entryPointFunc = runtime.FuncForPC(callerEntryPointProgramCounter)
callerFilePath, callPointLine = callPointFunc.FileLine(callPointProgramCounter)
_, callerEntryPointLine = entryPointFunc.FileLine(callerEntryPointProgramCounter)
stack = append(
stack,
CallerFrame{
StackIndex: k,
CallerFilePath: callerFilePath,
CallerName: callPointFunc.Name(),
CallerEntryPointProgramCounter: callerEntryPointProgramCounter,
CallerEntryPointLine: callerEntryPointLine,
CallPointProgramCounter: callPointProgramCounter,
CallPointLine: callPointLine,
},
)
}
}
return stack
}
fmt.Println(traceCallerStack(2, 32))
Proje Kök Dizini Bulucusu (Project Root Directory Finder)
// project/get_root_directory_path.go
package project
import (
"path"
"path/filepath"
"runtime"
)
func GetRootDirectoryPath() string {
_, f, _, _ := runtime.Caller(0)
d := path.Join(path.Dir(f))
return filepath.Dir(d)
}
Geçerli Çalışma Dizini Öğrenme (Current Working Directory - CWD)
…
Formatlama (Formatting)
Basma (Printing)
fmt.Println("Welcome\nHoşgeldin\nأهلا بك"); // String 'i stdout 'a yazar ve bir de yeni satır ekler
pt := struct { X, Y int }{ 1, 3 }
fmt.Println("Point:", pt, "X:", pt.X, "Y:", pt.Y) // Birden fazla Println çağırmak yerine bu şekilde tek bir Println çağrılabilir
s1 := fmt.Sprintln("Point:", pt, "X:", pt.X, "Y:", pt.Y)
// Yer tutuculara verb deniyor
fmt.Printf("dec: %d hex: %x bin: %b flp: %f sci: %e", 12, 12, 12, 12.0, 12.0) // c tarzı yer tutucular
s2 := fmt.Sprintf("dec: %d hex: %x bin: %b flp: %f sci: %e", 12, 12, 12, 12.0, 12.0)
// Verb'lerin hepsi: https://pkg.go.dev/fmt
welcomeMessages := `Welcome
Hoşgeldin
أهلا بك`
Stringer
Arayüzü
…
Formatter
Arayüzü
…
Düzenli İfadeler (Regular Expressions - RegEx - RegExp)
Tarih-Zaman Düzeni (Datetime Layout, Template, Format)
var tm time.Time
// ISO 8601
tm, _ = time.Parse("2006-01-02T15:04:05-07:00", "2022-05-04T08:07:06+03:00")
fmt.Println(tm.UTC().Format("2006-01-02T15:04:05-07:00")) // 2022-05-04T05:07:06+00:00
// ISO yalnız tarih
tm, _ = time.Parse("2006-01-02T15:04:05-07:00", "2022-05-04T08:07:06+03:00")
fmt.Println(tm.UTC().Format("2006-01-02")) // 2022-05-04
// ISO yalnız saat
tm, _ = time.Parse("2006-01-02T15:04:05-07:00", "2022-05-04T08:07:06+03:00")
fmt.Println(tm.UTC().Format("15:04:05")) // 05:07:06
// RFC 3339
tm, _ = time.Parse("2006-01-02T15:04:05Z07:00", "2022-05-04T08:07:06+03:00")
fmt.Println(tm.UTC().Format(time.RFC3339)) // 2022-05-04T05:07:06Z
// milisaniyeli RFC 3339
tm, _ = time.Parse("2006-01-02T15:04:05.999Z07:00", "2022-05-04T08:07:06.789+03:00")
fmt.Println(tm.UTC().Format("2006-01-02T15:04:05.999Z07:00")) // 2022-05-04T05:07:06.789Z
// mikrosaniyeli RFC 3339
tm, _ = time.Parse("2006-01-02T15:04:05.999999Z07:00", "2022-05-04T08:07:06.456789+03:00")
fmt.Println(tm.UTC().Format("2006-01-02T15:04:05.999999Z07:00")) // 2022-05-04T05:07:06.456789Z
// nanosaniyeli RFC 3339
tm, _ = time.Parse("2006-01-02T15:04:05.999999999Z07:00", "2022-05-04T08:07:06.123456789+03:00")
fmt.Println(tm.UTC().Format(time.RFC3339Nano)) // 2022-05-04T05:07:06.123456789Z
// noktalamasız ISO (karşılaştırılabilir)
tm, _ = time.Parse("20060102150405", "20220502050706")
fmt.Println(tm.UTC().Format("20060102150405")) // 20220502050706
// HTTP (RFC 1123 - GMT)
tm, _ = time.Parse("Mon, 02 Jan 2006 15:04:05 GMT", "Wed, 04 May 2022 05:07:06 GMT")
fmt.Println(tm.UTC().Format(http.TimeFormat)) // Wed, 04 May 2022 05:07:06 GMT
// RFC 1123
tm, _ = time.Parse("Mon, 02 Jan 2006 15:04:05 MST", "Wed, 04 May 2022 08:07:06 EEST")
fmt.Println(tm.UTC().Format(time.RFC1123)) // Wed, 04 May 2022 05:07:06 UTC
// nümerik zaman dilimli RFC 1123
tm, _ = time.Parse("Mon, 02 Jan 2006 15:04:05 -0700", "Wed, 04 May 2022 08:07:06 +0300")
fmt.Println(tm.UTC().Format(time.RFC1123Z)) // Wed, 04 May 2022 05:07:06 +0000
// ANSIC
tm, _ = time.Parse("Mon Jan _2 15:04:05 2006", "Wed May 4 05:07:06 2022")
fmt.Println(tm.UTC().Format(time.ANSIC)) // Wed May 4 05:07:06 2022
// Unix
tm, _ = time.Parse("Mon Jan _2 15:04:05 MST 2006", "Wed May 4 08:07:06 EEST 2022")
fmt.Println(tm.UTC().Format(time.UnixDate)) // Wed May 4 05:07:06 UTC 2022
// RFC 822
tm, _ = time.Parse("02 Jan 06 15:04 MST", "04 May 22 08:07 EEST")
fmt.Println(tm.UTC().Format(time.RFC822)) // 04 May 22 05:07 UTC
// nümerik zaman dilimli RFC 822
tm, _ = time.Parse("02 Jan 06 15:04 -0700", "04 May 22 08:07 +0300")
fmt.Println(tm.UTC().Format(time.RFC822Z)) // 04 May 22 05:07 +0000
// RFC 850
tm, _ = time.Parse("Monday, 02-Jan-06 15:04:05 MST", "Wednesday, 04-May-22 08:07:06 EEST")
fmt.Println(tm.UTC().Format(time.RFC850)) // Wednesday, 04-May-22 05:07:06 UTC
Dilim | 1. Seçenek | 2. Seçenek | 3. Seçenek | 4. Seçenek | 5. Seçenek | 6. Seçenek |
---|---|---|---|---|---|---|
Ay | 01 | 1 | Jan | January | ||
Gün | 02 | 2 | _2 | |||
Saat | 03 | 3 | _3 | 15 | ||
Dakika | 04 | 4 | _4 | |||
Saniye | 05 | 5 | _5 | |||
Yıl | 06 | 2006 | ||||
Bölge | -07 | -0700 | -07:00 | Z0700 | Z07:00 | MST |
Milisaniye | .000 | .999 | ||||
Mikrosaniye | .000000 | .999999 | ||||
Nanosaniye | .000000000 | .999999999 | ||||
Haftanın günü | Mon | Monday | ||||
Yarı gün | pm | PM |
Jenerik (Type Parameters - Generics)
…
Tipin Arayüzü (Interface of Type)
…
Çalışma Alanı (Workspaces)
…
Bağlam Kullanımı (Context Usage)
…
Birim Testleri (Unit Testing)
Test Fonksiyonu
Test dosyalarının adlarının sonunun _test.go
ile bitirilmesi önerilir:
// demo_test.go
package demo
import (
"testing" // Unit test için gereken paket
"github.com/stretchr/testify/assert" // İddia için gereken bir paket
)
func TestMyFunction(t *testing.T) { // Test fonksiyonunun adı "Test" ile başlar
expected := "Merhaba"
actual := MyFunction() // Aynı pakette (demo) bulunan teste tabi fonksiyon
assert.Equal(t, expected, actual) // Testin iddiası. Birden fazla iddia bulunabilir
}
Arayüz Taklitleme (Interface Mocking)
Taklitleyici Kurulumu (Mocker Installation)
go install github.com/golang/mock/mockgen@v1.5.0
Taklit Üretimi (Mock Generation)
// abc_service.go
// Mock 'a temel olacak interface 'i tanımlayalım
package abc
type AbcService interface {
Serve(s string) string
}
Taklit jeneratörünü bu dosya için çalıştıralım:
mockgen -source=abc/service.go -package=abcmock -destination=abc/mock/service_mock.go
Taklit Kullanım Örneği (Mock Usage)
package abc
import (
"fmt"
"testing"
abcmock "example.com/myspace/abc/mock"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert"
)
func TestAbcService(t *testing.T) {
mockController := gomock.NewController(t) // Mock controller ayarlar
defer mockController.Finish() // Mock controller sonlandırır
mockAbcService := abcmock.NewMockService(mockController) // mockgen ile oluşturulan taklit servis
mockAbcService.
EXPECT(). // Beklenen,
Serve(gomock.Any()). // 'Serve' herhangi bir girdi ile
Times(1). // 1 kereliğine çağrıldığında
Return("OK") // "OK" dönmesi
var err error
handler := NewHandler(mockAbcService) // Gerçek handler'a taklit servis enjekte ediliyor
err = handler.Handle() // Gerçek handler taklit servis ile çalıştırılıyor
assert.Nil(t, err) // Çalıştırma sonucunda hata yok iddiası
}
Fuzzing Test
…
Birim Testleri Koşturma
Yalnızca bulunulan dizindeki birim testlerin çalıştırılması için:
go test .
Bulunulan dizin ve alt dizinlerdeki tüm paketlerin birim testlerinin çalıştırılması için:
go test ./...