Go 1.26, Şubat 2026'da Go 1.25'ten altı ay sonra yayımlandı. Dil tarafında iki değişiklik var: yerleşik new fonksiyonu artık bir ifade alıp yeni değişkeni o değerle başlatabiliyor ve generic bir tip, kendi tip parametre listesinde kendisine başvurabiliyor. Araç tarafında go fix baştan yazıldı ve kodu güncel deyimlere taşıyan "modernizer"ların evi oldu. Çalışma zamanında ise Go 1.25'te deneysel olan Green Tea çöp toplayıcısı varsayılan hâle geldi.

Bu yazı yalnızca resmî Go 1.26 sürüm notlarına ve Go Blog duyurusuna dayanıyor. Dil ve kütüphane değişikliklerini Go 1.27.3 ile çalıştırdığımız örneklerle gösteriyoruz; 1.26'nın özellikleri sonraki sürümde de geçerli olduğu için çıktılar aynıdır. Bir sonraki sürümün değişiklikleri için Go 1.27 yenilikleri yazısına bakabilirsiniz.

new(ifade): başlangıç değeriyle işaretçi

new(ifade): başlangıç değeriyle işaretçi

Go 1.26'dan önce new yalnızca bir tip alırdı: new(int) sıfır değerli yeni bir int değişkeni ayırıp işaretçisini döndürürdü. Belirli bir değere işaretçi gerekiyorsa önce bir değişken tanımlayıp sonra adresini almak gerekirdi. Artık new'in argümanı bir ifade olabilir. Dil spesifikasyonuna göre new(x), x'in tipinde yeni bir değişken ayırır ve onu x'in değeriyle başlatır. Değer tipsiz bir sabitse önce varsayılan tipine çevrilir; new(123) bu yüzden *int döndürür. Önceden tanımlı nil tanımlayıcısı argüman olarak kullanılamaz.

go
package main

import (
	"encoding/json"
	"fmt"
)

type Kisi struct {
	Ad  string `json:"ad"`
	Yas *int   `json:"yas,omitempty"` // biliniyorsa yaş, değilse nil
}

func yasHesapla(dogumYili, buYil int) int { return buYil - dogumYili }

func main() {
	p := new(42)
	fmt.Println(*p)

	s := new("merhaba")
	f := new(int64(300))
	fmt.Printf("%T %T %v %v\n", s, f, *s, *f)

	b, _ := json.Marshal(Kisi{Ad: "Ayşe", Yas: new(yasHesapla(1990, 2026))})
	fmt.Println(string(b))
	b, _ = json.Marshal(Kisi{Ad: "Mert"})
	fmt.Println(string(b))
}

// Çıktı:
// 42
// *string *int64 merhaba 300
// {"ad":"Ayşe","yas":36}
// {"ad":"Mert"}

Sürüm notları bu özelliğin özellikle encoding/json ya da protocol buffers gibi, isteğe bağlı bir değeri işaretçiyle temsil eden serileştirme paketleriyle çalışırken yararlı olduğunu söyler. Örnekte Yas alanı *int: değer biliniyorsa bir sayıya işaret eder, bilinmiyorsa nil kalır ve omitempty sayesinde JSON'a hiç yazılmaz. Eskiden bu alanı tek bir ifadeyle doldurmak için yardımcı bir fonksiyon ya da geçici bir değişken gerekirdi; şimdi new(yasHesapla(1990, 2026)) yeterli. new(int64(300)) örneği de Go Blog duyurusundaki x := int64(300); ptr := &x kalıbının kısaltılmış hâlidir. İşaretçilerin genel kullanımı için pointer rehberine bakın.

Kendine başvuran generic tipler

İkinci dil değişikliği tip kısıtlarıyla ilgili. Önceden generic bir tip, kendi tip parametre listesinde kendi adını kullanamazdı. Go 1.26 bu kısıtlamayı kaldırdı; artık bir kısıt, kısıtlanan generic tipin kendisine başvurabiliyor. Sürüm notlarındaki örnek bir Adder arayüzüdür: kendisiyle aynı tipte bir değer alıp aynı tipte değer döndüren Add metodu ister. Aşağıda aynı fikri Türkçe adlarla ve çalışan bir Vektor tipiyle görüyorsunuz.

go
package main

import "fmt"

// Toplayici, kendisini tip parametresinde kullanan bir kısıt (Go 1.26 öncesi yasaktı).
type Toplayici[A Toplayici[A]] interface {
	Topla(A) A
}

func Topla[A Toplayici[A]](x, y A) A {
	return x.Topla(y)
}

type Vektor struct{ X, Y int }

func (v Vektor) Topla(w Vektor) Vektor { return Vektor{v.X + w.X, v.Y + w.Y} }

func main() {
	fmt.Println(Topla(Vektor{1, 2}, Vektor{10, 20}))
}

// Çıktı:
// {11 22}

Toplayici[A Toplayici[A]] ifadesi "A, kendisiyle toplanabilen bir tiptir" anlamına gelir. Sürüm notları, bu değişikliğin kısıtları daha güçlü yapmanın yanı sıra spesifikasyondaki tip parametresi kurallarını da biraz sadeleştirdiğini belirtir. Kısıt arayüzlerinin genel kullanımı için generics kısıtları yazısına bakabilirsiniz.

Yenilenen go fix ve modernizer'lar

Eski go fix komutu, çoğu artık geçersiz olan tarihî düzeltmeleri içeriyordu. Go 1.26'da komut tamamen yeniden yazıldı ve go vet ile aynı analiz çerçevesi üzerine kuruldu. Bu, go vet'te tanı üreten analizcilerin go fix'te düzeltme önerip uygulamak için de kullanılabileceği anlamına gelir. İlk sürümde dilin ve kütüphanenin yeni özelliklerinden yararlanan onlarca düzeltici (modernizer) ve //go:fix inline yönergesiyle işaretlenen fonksiyon çağrılarını satır içine alan bir kaynak düzeyi inliner var. Notlara göre bu düzelticiler programın davranışını değiştirmemelidir.

Eski usul yazılmış küçük bir dosya üzerinde go fix -diff ./... çalıştırdık. -diff bayrağı değişiklikleri uygulamak yerine bir fark (diff) olarak yazdırır ve fark boş değilse sıfırdan farklı bir çıkış koduyla döner.

go
package main

import "fmt"

func yazdir(v interface{}) {
	fmt.Println(v)
}

func main() {
	for i := 0; i < 3; i++ {
		yazdir(i)
	}
	x := 5
	if x > 3 {
		x = 3
	}
	yazdir(x)
}
text
--- main.go (old)
+++ main.go (new)
@@ -2,17 +2,14 @@
 
 import "fmt"
 
-func yazdir(v interface{}) {
+func yazdir(v any) {
 	fmt.Println(v)
 }
 
 func main() {
-	for i := 0; i < 3; i++ {
+	for i := range 3 {
 		yazdir(i)
 	}
-	x := 5
-	if x > 3 {
-		x = 3
-	}
+	x := min(5, 3)
 	yazdir(x)
 }

Üç düzeltme görüyorsunuz: interface{} yerine any, sayaçlı for yerine Go 1.22'den beri geçerli olan for i := range 3 ve elle yazılmış alt sınır yerine Go 1.21'in yerleşik min fonksiyonu. Değişiklikleri uygulamak için aynı komutu -diff olmadan çalıştırmanız yeterli; uygulamadan önce farkı okumak ve testleri çalıştırmak iyi bir alışkanlıktır. Go 1.27, atomictypes ve slicesbackward gibi yeni modernizer'lar ekledi. Araçların genel kullanımı go fmt, vet ve doc araçları yazısında.

go mod init ve diğer komut değişiklikleri

Go 1.26 notlarına göre go mod init, yeni go.mod dosyalarına varsayılan olarak bir alt Go sürümü yazar: 1.N.X sürümündeki bir araç zinciri go 1.(N-1).0 yazar (ör. Go 1.26 ile go 1.25.0); amaç, hâlâ desteklenen Go sürümleriyle uyumlu modüller oluşturulmasını teşvik etmektir. Bizim Go 1.27.3 ile yaptığımız denemede ise oluşan dosyada go 1.27.3 satırı vardı. Bu yüzden yeni bir modül oluşturduktan sonra go.mod'a bakıp sürümü bilinçli olarak seçmenizi, gerekirse notların önerdiği gibi go get go@sürüm kullanmanızı öneririz. Aynı sürümde cmd/doc ve go tool doc silindi; yerine aynı bayrak ve argümanları alan go doc kullanılıyor. pprof aracının web arayüzü artık varsayılan olarak alev grafiği (flame graph) görünümüyle açılıyor.

Çalışma zamanı: Green Tea çöp toplayıcısı ve diğerleri

Çalışma zamanı: Green Tea çöp toplayıcısı ve diğerleri: cgo çağrılarının temel çalışma zamanı ek yükü yaklaşık yüzde 30 azaldı., 64 bit platformlarda çalışma zamanı, başlangıçta...

Go 1.25'te deneysel olan Green Tea çöp toplayıcısı Go 1.26 ile varsayılan oldu. Tasarımı küçük nesnelerin işaretlenmesini ve taranmasını daha iyi bellek yerelliği ve CPU ölçeklenebilirliğiyle hızlandırıyor. Sürüm notları, çöp toplayıcıyı yoğun kullanan gerçek programlarda çöp toplama ek yükünde yüzde 10 ile 40 arasında bir azalma beklediklerini, sonuçların ise iş yüküne göre değiştiğini söyler; yeni amd64 işlemcilerde (Intel Ice Lake, AMD Zen 4 ve sonrası) vektör komutları sayesinde yüzde 10 civarında ek kazanç bekleniyor. Yeni toplayıcı derleme sırasında GOEXPERIMENT=nogreenteagc ile kapatılabiliyordu; notlara göre bu seçeneğin Go 1.27'de kaldırılması planlanıyordu.

  • cgo çağrılarının temel çalışma zamanı ek yükü yaklaşık yüzde 30 azaldı.
  • 64 bit platformlarda çalışma zamanı, başlangıçta heap taban adresini rastgele seçiyor; bu, cgo kullanan programlarda bellek adreslerini tahmin etmeyi zorlaştıran bir güvenlik iyileştirmesi.
  • Derleyici, dilimlerin arka belleğini daha fazla durumda yığında (stack) ayırabiliyor. Sorun çıkarsa notlar bisect aracını ve -gcflags=all=-d=variablemakehash=n bayrağını öneriyor.
  • Deneysel goroutineleak profili, hiçbir zaman uyanamayacak biçimde bloke olmuş goroutine'leri çöp toplayıcının erişilebilirlik bilgisini kullanarak buluyor; Go 1.27'de genel kullanıma açıldı.

Goroutine sızıntısı profilinin notlardaki örneği öğreticidir: tamponsuz bir kanala sonuç gönderen birkaç goroutine başlatılır, sonuçları toplayan fonksiyon ilk hatada erken return eder ve kalan goroutine'ler gönderim yapamayacakları için sonsuza dek bekler. Bu hatanın nasıl önleneceği channel rehberinde ve context paketi yazısında anlatılıyor.

Standart kütüphane: öne çıkan eklemeler

Standart kütüphane: öne çıkan eklemeler: crypto paketlerinde rastgelelik parametresi artık yok sayılıyor..., Yeni crypto/hpke paketi RFC 9180 Hybrid Public Key Encryption'ı...

Aşağıdaki örnek dört küçük ama günlük kodda işe yarayan eklemeyi bir arada gösteriyor. errors.AsType, errors.As'ın generic sürümüdür; notlara göre tip güvenli, daha hızlı ve çoğu durumda kullanımı daha kolaydır, çünkü hedef değişkeni önceden tanımlayıp adresini vermeniz gerekmez. bytes.Buffer.Peek sıradaki n baytı tamponu ilerletmeden döndürür. reflect paketine bir struct tipinin alanları, metotları, fonksiyon girdi ve çıktıları üzerinde iterator döndüren Type.Fields, Type.Methods, Type.Ins, Type.Outs ile Value.Fields ve Value.Methods eklendi. net/url.Parse ise artık konak bölümünde iki nokta içeren bozuk URL'leri reddediyor; köşeli parantezli IPv6 adresleri kabul edilmeye devam ediyor.

go
package main

import (
	"bytes"
	"errors"
	"fmt"
	"io/fs"
	"net/url"
	"os"
	"reflect"
)

type Ayar struct {
	Port  int
	Debug bool
}

func main() {
	_, err := os.Open("olmayan-dosya.txt")
	if pe, ok := errors.AsType[*fs.PathError](err); ok {
		fmt.Println("işlem:", pe.Op, "| yol:", pe.Path)
	}

	var buf bytes.Buffer
	buf.WriteString("GET /index")
	ilk, _ := buf.Peek(3)
	fmt.Printf("%s %d\n", ilk, buf.Len())

	for alan := range reflect.TypeFor[Ayar]().Fields() {
		fmt.Println(alan.Name, alan.Type)
	}

	_, err = url.Parse("http://localhost:80:80/")
	fmt.Println(err != nil)
	u, err := url.Parse("http://[::1]/")
	fmt.Println(u.Host, err)
}

// Çıktı:
// işlem: open | yol: olmayan-dosya.txt
// GET 10
// Port int
// Debug bool
// true
// [::1] <nil>

Bir hatanın belirli bir tipte olup olmadığını öğrenmenin klasik yolu için hata yönetimi yazısına, iterator'lerin nasıl dolaşıldığı için range over func yazısına bakabilirsiniz. Eski URL davranışına geçici olarak dönmek gerekirse notlar urlstrictcolons=0 GODEBUG ayarını verir.

log/slog: NewMultiHandler

slog.NewMultiHandler, verilen tüm handler'ları çağıran bir MultiHandler oluşturur. Enabled metodu handler'lardan herhangi biri etkinse true döner; Handle, WithAttrs ve WithGroup ise yalnızca etkin handler'larda karşılık gelen metodu çağırır. Aşağıda metin handler'ı tüm kayıtları, JSON handler'ı ise yalnızca uyarı ve üstünü alıyor. Çıktı sabit kalsın diye zaman alanını ReplaceAttr ile çıkardık.

go
package main

import (
	"bytes"
	"fmt"
	"log/slog"
)

func main() {
	var metin, js bytes.Buffer
	sadeMetin := func(groups []string, a slog.Attr) slog.Attr {
		if a.Key == slog.TimeKey && len(groups) == 0 {
			return slog.Attr{}
		}
		return a
	}
	h := slog.NewMultiHandler(
		slog.NewTextHandler(&metin, &slog.HandlerOptions{ReplaceAttr: sadeMetin}),
		slog.NewJSONHandler(&js, &slog.HandlerOptions{Level: slog.LevelWarn, ReplaceAttr: sadeMetin}),
	)
	log := slog.New(h)
	log.Info("sunucu başladı", "port", 8080)
	log.Warn("disk dolmak üzere", "yuzde", 91)

	fmt.Print(metin.String())
	fmt.Print(js.String())
}

// Çıktı:
// level=INFO msg="sunucu başladı" port=8080
// level=WARN msg="disk dolmak üzere" yuzde=91
// {"level":"WARN","msg":"disk dolmak üzere","yuzde":91}

Handler seçenekleri ve seviyeler için log/slog rehberine bakabilirsiniz.

Diğer kütüphane değişiklikleri

  • crypto paketlerinde rastgelelik parametresi artık yok sayılıyor: rsa.GenerateKey, ecdsa.GenerateKey, ecdh.Curve.GenerateKey, rand.Prime ve benzerleri her zaman güvenli bir kaynak kullanıyor. Deterministik testler için yeni testing/cryptotest.SetGlobalRandom öneriliyor; cryptocustomrand=1 GODEBUG ayarı eski davranışı geçici olarak geri getiriyor.
  • Yeni crypto/hpke paketi RFC 9180 Hybrid Public Key Encryption'ı uyguluyor. crypto/tls'de kuantum sonrası hibrit SecP256r1MLKEM768 ve SecP384r1MLKEM1024 anahtar değişimleri varsayılan olarak açık.
  • io.ReadAll daha az ara bellek ayırıyor ve sonuç dilimini en küçük boyutta döndürüyor; notlara göre çoğu zaman yaklaşık iki kat hızlı. fmt.Errorf("x") gibi biçimlendirme içermeyen çağrılar artık errors.New("x") kadar az ayırma yapıyor.
  • net/http: ServeMux'un sondaki eğik çizgi yönlendirmeleri 301 yerine 307 (Temporary Redirect) kullanıyor; Client çerez kapsamında mümkünse Request.Host değerini kullanıyor. httputil.ReverseProxy.Director güvenlik nedeniyle kullanımdan kaldırıldı, yerine Rewrite öneriliyor. Sunucu yazımı için net/http web sunucusu yazısına bakın.
  • net/http/httptest: Server.Client ile alınan istemci, example.com ve alt alan adlarına giden istekleri test sunucusuna yönlendiriyor.
  • os/signal.NotifyContext, döndürdüğü context'i hangi sinyalin alındığını belirten bir nedenle (cause) iptal ediyor.
  • testing: T.ArtifactDir, B.ArtifactDir ve F.ArtifactDir test çıktı dosyaları için bir dizin döndürüyor; go test -artifacts verilirse dizin çıktı dizininde kalıyor. B.Loop artık döngü gövdesinde satır içine almayı engellemiyor; notlara göre tüm benchmark'lar eski b.N biçiminden B.Loop biçimine sorunsuz taşınabilir. Ayrıntılar benchmark ve fuzz yazısında.
  • image/jpeg kodlayıcı ve çözücüsü daha hızlı ve daha doğru yeni uygulamalarla değiştirildi; bit bit aynı çıktı bekleyen kodların güncellenmesi gerekebilir.

Deneysel özellikler ve platformlar

Go 1.26 bazı paketleri yalnızca açıkça istendiğinde etkinleşen deney olarak sundu: amd64 üzerinde 128, 256 ve 512 bit vektör tipleri sağlayan simd/archsimd (GOEXPERIMENT=simd), gizli bilgi işleyen kodun geçici verilerini güvenli biçimde silmeye yarayan runtime/secret (GOEXPERIMENT=runtimesecret, Linux üzerinde amd64 ve arm64) ve yukarıda değinilen goroutine sızıntısı profili. Platform tarafında Go 1.26, macOS 12 Monterey'de çalışan son sürüm oldu; daha önce bozuk ilan edilen 32 bit windows/arm portu kaldırıldı, freebsd/riscv64 bozuk olarak işaretlendi, linux/riscv64 yarış dedektörü desteği kazandı ve s390x fonksiyon argümanlarını yazmaçlarla geçirmeye başladı.

Notlar ayrıca bir sonraki sürüm için uyarılar içeriyordu: asynctimerchan, gotypesalias ve bazı TLS GODEBUG ayarlarının Go 1.27'de kaldırılacağı duyuruldu ve Go 1.27 notları bunların gerçekten kaldırıldığını doğruluyor. Kodunuz bu ayarlara dayanıyorsa 1.26, geçişi hazırlamak için doğru durak.

Sık yapılan hatalar

new'e nil ya da tip yerine yanlış şey vermek

new(nil) geçersizdir; spesifikasyon önceden tanımlı nil'in new argümanı olamayacağını açıkça söyler. Tipsiz sabitlerin varsayılan tipe dönüştüğünü de unutmayın: new(1.5) bir *float64, new('a') bir *int32 (rune) döndürür. Başka bir tip istiyorsanız dönüşümü açıkça yazın: new(float32(1.5)).

go fix çıktısını incelemeden uygulamak

Modernizer'ların davranışı değiştirmemesi amaçlanır ve notlar bir sorunla karşılaşırsanız bildirmenizi ister. Yine de büyük bir kod tabanında önce -diff ile farkı görmek, ardından uygulayıp testleri çalıştırmak hatayı erken yakalar.

Deterministik test için crypto rastgelelik parametresine güvenmek

Testlerde rsa.GenerateKey'e sabit bir okuyucu verip aynı anahtarı beklemek Go 1.26'dan itibaren çalışmaz, çünkü parametre yok sayılır. Notların önerisi testing/cryptotest.SetGlobalRandom kullanmaktır.

Yönlendirme koduna bağlı testler

ServeMux'un sondaki eğik çizgi yönlendirmeleri artık 307 döndürüyor. Testleriniz 301 bekliyorsa güncellenmeleri gerekir.

Sık Sorulan Sorular

new(ifade) ile &amp;değişken arasında fark var mı?

Sonuç ikisinde de bir işaretçidir. new(ifade) her çağrıda yeni bir değişken oluşturur ve değeri ifadeden kopyalar; &degisken ise var olan bir değişkenin adresini verir. Aynı değişkeni paylaşmak istiyorsanız adres alın, bağımsız bir kopya istiyorsanız new kullanın.

Green Tea çöp toplayıcısını kapatmalı mıyım?

Notlar, yeni toplayıcıyı performans ya da davranış nedeniyle kapatırsanız bir sorun kaydı açmanızı ister; kapatma seçeneği geçiş dönemi içindir. Önce kendi iş yükünüzde ölçüm yapın.

errors.As yerine her zaman AsType mı kullanmalıyım?

Notlara göre AsType tip güvenli, daha hızlı ve çoğu durumda daha kolaydır. errors.As kaldırılmadı; mevcut kod çalışmaya devam eder. Yeni kodda AsType daha kısa ve okunaklı sonuç verir.

Go 1.26 özelliklerini kullanmak için go.mod'da ne yazmalı?

new(ifade) ve kendine başvuran tipler dil özellikleridir, bu yüzden modülün go satırı en az 1.26 olmalıdır. Satırı değiştirmek için go mod edit -go=1.26 ya da go get go@1.26 kullanılabilir; ayrıntılar go mod rehberinde ve Go öğrenme rehberinde.

Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.

İlgili içerikler: Go öğrenme rehberi · Go 1.27 yenilikleri · pointer ve new · go fix ve diğer araçlar · generics kısıtları · Go nedir?