go
Go dersleri
Go/Temeller

Go'ya Giriş

Go'nun felsefesi, kurulum, ilk program ve temel araçlar.

Ders 1 / 2115 dkBaşlangıç
Bu derste öğreneceklerin
  • Go'nun tarihçesi ve tasarım felsefesi
  • Kurulum ve go version
  • go mod init ile modül oluşturma
  • package main ve func main
  • go run, go build, gofmt ve go vet
  • fmt.Println ve fmt.Printf biçimlendirme fiilleri
  • Yorum satırları

Yeni bir dil öğrenmeye başlarken en çok merak edilen şey genelde sözdizimidir: Döngü nasıl yazılır, fonksiyon nasıl tanımlanır? Oysa bir dili gerçekten anlamak için önce neden var olduğunu bilmek gerekir. Go, 2007'de Google'da üç mühendisin — Robert Griesemer, Rob Pike ve Ken Thompson — büyük bir C++ projesinin derlenmesini beklerken duydukları sıkıntıdan doğdu. Milyonlarca satırlık kod tabanları yavaş derleniyor, bağımlılıklar içinden çıkılmaz hale geliyor, çok çekirdekli makinelerden verim almak zorlaşıyordu.

Go'nun cevabı radikal biçimde basit oldu: Dili küçük tut, derlemeyi saniyeler içinde bitir, eşzamanlılığı dilin kendisine koy. Bugün Docker, Kubernetes, Terraform, Prometheus gibi altyapı dünyasının bel kemiği olan araçlar Go ile yazılmış durumda. Go'nun 25 anahtar kelimesi vardır; C++'ın 90'dan fazla. Bu azlık bir eksiklik değil, bilinçli bir tercihtir: Kodu okuyan kişi, yazandan daha önemlidir.

Bu derste Go'yu kuracak, ilk modülünü oluşturacak, ilk programını yazıp çalıştıracaksın. Ardından her Go geliştiricisinin günde onlarca kez kullandığı araçları — go run, go build, gofmt, go vet — ve ekrana yazdırmanın tüm yollarını öğreneceksin. Dersin sonunda kendi makinende çalışan, biçimi standartlara uygun, denetimden geçmiş bir Go programın olacak.

Go'nun tasarım felsefesi

Go'yu diğer dillerden ayıran birkaç kararlı tercih vardır. Bunları baştan bilmek, ilerideki derslerde "neden böyle?" sorusunu azaltır:

  • Az özellik, çok netlik. Go'da sınıf, kalıtım, istisna (exception), operatör aşırı yüklemesi ve — uzun süre — jenerikler yoktu. Jenerikler 1.18'de eklendi ama diğerleri hâlâ yok. Bir problemi çözmenin genelde tek bir bariz yolu vardır.
  • Tek bir biçim. gofmt aracı kodu tek bir standart biçime sokar. Go dünyasında girinti tartışması yapılmaz; tartışmayı araç bitirmiştir.
  • Hatalar değerdir. Bir işlem başarısız olabiliyorsa fonksiyon ikinci bir dönüş değeri olarak error döndürür. try/catch yoktur; hata yolu kodun görünür bir parçasıdır.
  • Eşzamanlılık dilin içindedir. go anahtar kelimesiyle bir fonksiyonu ayrı bir yürütme akışında başlatırsın. Bunun için kütüphane gerekmez.
  • Derleme hızlıdır. Kullanılmayan bir import veya değişken bile derleme hatasıdır. Sert görünür ama kod tabanını temiz ve derlemeyi hızlı tutar.
  • Statik derleme. Go, tek bir çalıştırılabilir dosya üretir. Sunucuya kopyala ve çalıştır; ayrı bir çalışma zamanı kurmana gerek yoktur.

Kurulum ve doğrulama

go.dev/dl adresinden işletim sistemine uygun kurulum dosyasını indir. macOS'ta .pkg, Windows'ta .msi, Linux'ta ise arşivi /usr/local altına açman yeterlidir. Kurulumdan sonra terminalde:

go version

Beklenen çıktı buna benzer bir satırdır (sürüm ve platform sende farklı olabilir):

go version go1.26.0 darwin/arm64

Bu satırı görüyorsan Go kurulmuş ve PATH'e eklenmiş demektir. Komut bulunamıyorsa Go'nun bin dizinini PATH'e eklemen gerekir. Kurulumun ayrıntılarını görmek için:

go env GOROOT GOPATH GOMODCACHE

GOROOT Go'nun kurulu olduğu yeri, GOPATH indirilen paketlerin ve araçların yerini gösterir. Modüller çıktıktan sonra GOPATH'in önemi büyük ölçüde azaldı; projelerini artık istediğin dizinde tutabilirsin.

Modül oluşturma: go mod init

Go'da her proje bir modüldür (module). Modül, birlikte sürümlenen paketlerin kökünü ve bağımlılıklarını tanımlar. Yeni bir proje başlatmak iki komut sürer:

mkdir merhaba
cd merhaba
go mod init example.com/merhaba

Bu, dizinde go.mod adlı bir dosya oluşturur:

module example.com/merhaba

go 1.26

İlk satır modülün yolunu, ikinci satır hedeflenen Go sürümünü belirtir. Modül yolu genelde kodun yayımlanacağı adrestir (github.com/kullanici/proje gibi). Yalnızca kendi makinende deneme yapıyorsan example.com/merhaba gibi bir ad yeterlidir; önemli olan başka modüllerle çakışmamasıdır.

Projene dışarıdan bir paket eklediğinde go.mod dosyasına bir require satırı, dizine de bağımlılıkların kriptografik özetlerini tutan go.sum dosyası eklenir. Paketler ve modüller konusunu Paketler ve Modüller dersinde ayrıntılı işleyeceğiz.

İlk program: package main ve func main

Dizinde main.go adında bir dosya oluştur:

main.go
package main

import "fmt"

func main() {
	fmt.Println("Merhaba, dünya!")
}
Çıktı
Merhaba, dünya!

Bu altı satırın her parçası önemlidir:

  • package main — Her Go dosyası bir pakete aittir ve ilk satırda bunu bildirir. main özel bir pakettir: Derleyici yalnızca main paketinden çalıştırılabilir bir program üretir. Adı başka bir şey olsaydı (package hesap gibi) bu kod bir kütüphane olurdu.
  • import "fmt" — Standart kütüphanedeki fmt (format) paketini içeri alır. Biçimli giriş/çıkış işlemleri bu paketten gelir. Go'da içeri aldığın ama kullanmadığın bir paket derleme hatasıdır.
  • func main() — Programın giriş noktasıdır. Parametre almaz, değer döndürmez. main fonksiyonu bittiğinde program da biter.
  • fmt.Println(...) — Paket adı, nokta ve fonksiyon adı. Büyük harfle başlayan isimler (Println) paket dışından erişilebilir, küçük harfle başlayanlar erişilemez. Go'da public/private anahtar kelimeleri yoktur; görünürlüğü ismin ilk harfi belirler.

Go'da satır sonlarına noktalı virgül koymazsın. Aslında dil bunları ister, ama derleyici satır sonlarına kendisi ekler. Bunun bir yan etkisi vardır: Açılış süslü parantezi ({) mutlaka aynı satırda kalmalıdır. Aşağıdaki gibi bir yazım derlenmez:

func main()
{ // HATA: syntax error: unexpected semicolon or newline before {
	fmt.Println("...")
}

Araç zinciri: run, build, fmt, vet

Go'nun tek bir go komutu vardır; alt komutlarıyla derler, çalıştırır, biçimlendirir, test eder ve bağımlılıkları yönetir. Günlük hayatta en çok kullanacakların şunlardır:

KomutNe yapar
go run .Dizindeki main paketini derleyip hemen çalıştırır, geçici dosyayı siler
go buildÇalıştırılabilir dosya üretir (dizin adıyla, Windows'ta .exe uzantılı)
go build -o bin/appÇıktının adını ve yerini sen belirlersin
gofmt -l .Biçimi standart dışı olan dosyaları listeler
gofmt -w .Dosyaları standart biçime göre düzeltir
go vet ./...Derlenen ama muhtemelen hatalı olan kod desenlerini yakalar
go test ./...Testleri çalıştırır
go doc fmt.PrintfBir paketin veya fonksiyonun belgesini terminalde gösterir

./... yazımı "bu dizin ve altındaki tüm paketler" anlamına gelir; büyük projelerde her yeri tek komutla taramak için kullanılır.

gofmt: biçim tartışması yok

gofmt girintiyi sekme ile yapar, operatörlerin etrafındaki boşlukları düzenler, yapıları hizalar. Editörün Go eklentisi genelde kaydettiğin anda gofmt (ya da eşdeğeri go fmt) çalıştırır. Biçim bozuk bir dosyayı düzeltmek için:

gofmt -w main.go

Değişikliği uygulamadan farkı görmek istersen -d bayrağını kullan: gofmt -d main.go.

go vet: derleyicinin bakmadığı yere bakar

Derleyici sözdizimini ve tipleri kontrol eder; ama bazı hatalar tip açısından geçerlidir. go vet bu tür şüpheli desenleri yakalar. Klasik örnek, Printf fiilleriyle argümanların uyuşmamasıdır:

fmt.Printf("%d yaş\n", "otuz") // vet: arg "otuz" for %d of wrong type: string
fmt.Println("%d yaş\n", 30)    // vet: Println call has possible Printf formatting directive

İkisi de derlenir, ikisi de yanlıştır. go vet ./... komutunu düzenli çalıştırmayı alışkanlık haline getir.

Ekrana yazdırma: Println ve Printf

fmt paketinin üç temel yazdırma ailesi vardır. Farkı anlamak ilk günden işini kolaylaştırır:

  • Print — Argümanları olduğu gibi yazar, satır sonu eklemez.
  • Println — Argümanların arasına boşluk koyar ve sonuna satır sonu ekler.
  • Printf — Bir biçim dizesi (format string) alır; % ile başlayan fiiller (verbs) argümanların nasıl yazılacağını belirler.
main.go
package main

import "fmt"

func main() {
	name := "Zeynep"
	age := 28
	height := 1.6543
	active := true

	fmt.Print("satır sonu yok")
	fmt.Print(" | araya boşluk koymaz\n")
	fmt.Println(name, age, active) // araya boşluk koyar, satır sonu ekler

	fmt.Printf("%s %d yaşında\n", name, age)
	fmt.Printf("boy: %.2f m\n", height)             // 2 basamak
	fmt.Printf("%v | %v | %v\n", name, age, active) // varsayılan biçim
	fmt.Printf("%q ve %T\n", name, height)          // tırnaklı metin ve tip
	fmt.Printf("%5d|%-5d|%05d|\n", 42, 42, 42)      // genişlik ve hizalama
	fmt.Printf("ikilik: %b, onaltılık: %x\n", 200, 200)
	fmt.Printf("yüzde işareti: %%\n")
}
Çıktı
satır sonu yok | araya boşluk koymaz
Zeynep 28 true
Zeynep 28 yaşında
boy: 1.65 m
Zeynep | 28 | true
"Zeynep" ve float64
   42|42   |00042|
ikilik: 11001000, onaltılık: c8
yüzde işareti: %

En sık kullanacağın fiiller:

FiilAnlamıÖrnek çıktı
%vDeğerin varsayılan gösterimi28, true, [1 2 3]
%+vStruct'larda alan adlarıyla\{Name:Ali Age:30\}
%TDeğerin tipifloat64
%dTam sayı (onluk)42
%f, %.2fOndalık sayı1.654300, 1.65
%sMetinZeynep
%qTırnak içinde metin"Zeynep"
%tBooleantrue
%b, %o, %x, %X2'lik, 8'lik, 16'lık taban11001000, c8
%c, %URune ve Unicode koduş, U+015F
%pİşaretçi adresi0xc000012345
%%Yüzde işaretinin kendisi%

Yazdırmak yerine metni bir değişkende tutmak istersen Sprintf ailesini kullanırsın; Fprintf ise çıktıyı bir dosyaya veya hata akışına yazar:

main.go
package main

import (
	"fmt"
	"os"
)

func main() {
	total := 3
	msg := fmt.Sprintf("%d dosya işlendi", total) // yazdırmaz, döndürür
	fmt.Println(msg)
	fmt.Println(len(msg), "bayt")

	fmt.Fprintln(os.Stdout, "standart çıktıya")
	fmt.Fprintln(os.Stderr, "standart hataya") // günlük ve hata mesajları buraya
}
Çıktı
3 dosya işlendi
16 bayt
standart çıktıya
standart hataya

Yorum satırları

Go iki yorum biçimini destekler:

// Tek satırlık yorum: satır sonuna kadar geçerlidir.

/*
   Blok yorum: birden çok satır.
   İç içe yazılamaz.
*/

Pratikte Go kodunda neredeyse her zaman // kullanılır. Blok yorumlar genelde dosya başındaki telif/lisans notlarına ayrılır.

Bir tanımın (paket, fonksiyon, tip, değişken) hemen üstüne yazılan yorumlar belge yorumu (doc comment) sayılır; go doc ve pkg.go.dev bunları okur. Kural, yorumun tanımlanan adla başlamasıdır:

// Package hesap basit finansal hesaplamalar sağlar.
package hesap

// KDVEkle, verilen tutara oran kadar KDV ekleyip sonucu döndürür.
// oran 0.20 gibi ondalık bir değer olarak verilir.
func KDVEkle(tutar, oran float64) float64 {
	return tutar * (1 + oran)
}

Yorumların ne yaptığını değil, neden öyle yapıldığını anlatması iyi bir alışkanlıktır. i++ satırının yanına "i'yi bir artır" yazmak kimseye bir şey katmaz.

Sık yapılan hatalar

  • Kullanılmayan import veya değişken bırakmak. imported and not used: "os" ya da declared and not used: x hatası alırsın. Deneme yaparken geçici olarak _ = x yazabilirsin ama kalıcı çözüm satırı silmektir.
  • Açılış parantezini alt satıra almak. Go, satır sonlarına otomatik noktalı virgül ekler; { mutlaka aynı satırda kalmalıdır.
  • Println içinde biçim fiili kullanmak. fmt.Println("%d adet", n) metni olduğu gibi yazar. Biçimlendirme istiyorsan Printf kullan ve satır sonunu (\n) kendin ekle.
  • go run main.go ile tek dosya çalıştırmak. Projede birden çok dosya varsa eksik tanım hatası alırsın. go run . tüm paketi derler.
  • Dosyayı go mod init yapmadan bir dizine koymak. Modül dışında go run çalışmaz; hata mesajı doğrudan go mod init önerir.
  • Dışa açılacak ismi küçük harfle başlatmak. func toplam() başka paketlerden görünmez; func Toplam() görünür.

Alıştırmalar

Alıştırma·Kartvizit
Kolay

Adını, yaşını ve bir hobini değişkenlerde tutan; ardından şu üç satırı yazdıran bir program yaz:

Ad: Elif
Yaş: 24
Hobi: dalış

İlk satırda Println, ikinci ve üçüncü satırlarda Printf kullan.

İpucu

Printf'in sonuna \n koymayı unutma; Println'den farklı olarak satır sonunu kendisi eklemez.

Çözümü göster
main.go
package main

import "fmt"

func main() {
	name := "Elif"
	age := 24
	hobby := "dalış"

	fmt.Println("Ad:", name)
	fmt.Printf("Yaş: %d\n", age)
	fmt.Printf("Hobi: %s\n", hobby)
}
Çıktı
Ad: Elif
Yaş: 24
Hobi: dalış

Println argümanların arasına otomatik boşluk koyduğu için "Ad:" ile isim arasında boşluk oluşur. Printf'te boşluğu biçim dizesinin kendisi sağlar.

Alıştırma·Fiş yazdırma
Orta

Bir ürünün adını, adedini ve birim fiyatını alıp aşağıdaki gibi hizalı bir fiş satırı yazdır. Ürün adı sola yaslı 12 karakter, adet sağa yaslı 3 karakter, tutar iki ondalık basamaklı olsun. Toplam tutarı Sprintf ile bir değişkende oluştur ve sonra yazdır.

Ürün         Adet     Tutar
kalem           3     37.50
İpucu

Sola yaslamak için %-12s, sağa yaslamak için %3d, iki basamak için %8.2f kullan.

Çözümü göster
main.go
package main

import "fmt"

func main() {
	name := "kalem"
	count := 3
	unitPrice := 12.5

	total := float64(count) * unitPrice

	fmt.Printf("%-12s %4s %9s\n", "Ürün", "Adet", "Tutar")
	line := fmt.Sprintf("%-12s %4d %9.2f", name, count, total)
	fmt.Println(line)
}
Çıktı
Ürün         Adet     Tutar
kalem           3     37.50

count bir int, unitPrice bir float64 olduğu için çarpmadan önce float64(count) dönüşümü gerekir: Go farklı tipleri örtük olarak dönüştürmez. Sprintf metni döndürür, böylece satırı yazdırmadan önce saklayabilir veya değiştirebilirsin.

Sekizli hizalamada Türkçe karakterlerin birden fazla bayt tuttuğunu unutma; %-12s genişliği rune değil bayt sayar. Bu ayrıntıyı Stringler ve Rune'lar dersinde göreceksin.

Alıştırma·Tip ve taban tablosu
Zor

Bir tam sayı, bir ondalık sayı, bir metin ve bir boolean değer için her satırda değerin kendisini (%v) ve tipini (%T) hizalı biçimde yazdıran bir program yaz. Metin için ayrıca tırnaklı gösterimi (%q), tam sayı için de 2'lik, 8'lik ve 16'lık tabandaki karşılıklarını göster.

İpucu

Sütunları hizalamak için %-10v ve %-10T gibi genişlikli fiiller kullan. Taban dönüşümleri için %b, %o ve %x yeterli; sıfır dolgusu istersen %08b yaz.

Çözümü göster
main.go
package main

import "fmt"

func main() {
	n := 42
	f := 3.14159
	s := "Go"
	b := true

	fmt.Printf("%-10v %-10T\n", n, n)
	fmt.Printf("%-10v %-10T\n", f, f)
	fmt.Printf("%-10v %-10T %q\n", s, s, s)
	fmt.Printf("%-10v %-10T\n", b, b)

	fmt.Printf("\n%d sayısı: 2'lik %b, 8'lik %o, 16'lık %x\n", n, n, n, n)
	fmt.Printf("sıfır dolgusu: %08b\n", n)
}
Çıktı
42         int
3.14159    float64
Go         string     "Go"
true       bool

42 sayısı: 2'lik 101010, 8'lik 52, 16'lık 2a
sıfır dolgusu: 00101010

%v her tip için makul bir varsayılan gösterim üretir; %T tipin adını yazar ve tip dönüşümü hatalarını ayıklarken çok işine yarar. %q yalnızca metin (ve rune) için anlamlıdır: Bir int ile kullanırsan program çökmez, çıktıya %!q(int=42) gibi bir işaret koyar ve go vet bunu "wrong type" diye uyarır.

Kısa sınav

Kısa sınav

Bir Go dosyasının ilk satırındaki package main bildirimi ne anlama gelir?

fmt.Println("%d adet", 3) ne yazdırır?

gofmt aracının Go ekosistemindeki rolü nedir?

Aşağıdakilerden hangisi Go'da derleme hatasına yol açar?

go run . ile go build arasındaki temel fark nedir?

Bir fonksiyonun başka paketlerden erişilebilir olmasını ne belirler?

Özet

  • Go, büyük kod tabanlarında derleme hızı, okunabilirlik ve eşzamanlılık sorunlarına cevap olarak tasarlandı; az sayıda özellikle çok iş yapmayı hedefler.
  • Her proje bir modüldür; go mod init <yol> ile go.mod dosyası oluşturulur.
  • Çalıştırılabilir program için dosya package main ile başlar ve func main() içerir; büyük harfle başlayan isimler dışa açıktır.
  • go run . geliştirirken, go build dağıtım için kullanılır; gofmt biçimi, go vet şüpheli desenleri, go test testleri yönetir.
  • Println basit yazdırma, Printf biçimli yazdırma, Sprintf metin döndürme içindir; en sık kullanılan fiiller %v, %d, %s, %q, %T ve %.2f'tir.
  • Kullanılmayan import ve yerel değişkenler derleme hatasıdır; bu katılık kod tabanını temiz tutar.
  • Belge yorumları tanımın hemen üstüne yazılır ve tanımlanan adla başlar; go doc ve pkg.go.dev bu yorumları gösterir.
Bu dersi bitirdin mi?
İlerlemen bu tarayıcıda saklanır.