---
id: 1a31e06c0d969b4b6cbbc590259cf089
author: iwanhae
title: Go 1.27 ya da Endişelenmeyi Bırakmayı ve Jenerik Metotları Sevmeyi Nasıl Öğrendim
description: Jenerik metotlar, encoding/json/v2, standart bir uuid paketi ve gerçekten çalışan bir goroutine sızıntı dedektörü. Tüm örneklerin gerçekten çalıştırıldığı, Go 1.27 üzerine bir inceleme.
language: tr
date: 2026-08-15T02:08:43.129534158Z
path: /blog/posts/go-1-27-or-how-i-learned-to-stop-worrying-and-love-generic-methods-za800e454
category: release
---

![Go 1.27'ye genel bakış](/assets/images/whats-new-in-go1.27/overview.webp)

Go 1.27, Ağustos 2026'da yayımlanıyor ve bu kez dil kendisi değişti. "`slices` paketine yeni bir fonksiyon ekledik" türünden bir değişiklik değil, gerçekten bir değişiklik. Genel metotlar (generic methods) dile girdi. On bir yıllık bir issue kapatıldı. `encoding/json`, uçak havadayken sessizce yeni bir motorla değiştirildi.

Aşağıdaki her örnek `go1.27rc3` (darwin/arm64) üzerinde çalıştırıldı. Her çıktı bloğu gerçek çıktıdır, hata mesajları dahil olmak üzere kopyalanıp yapıştırılmıştır. Bir şey garip görünüyorsa, bunun nedeni derleyicinin gerçekten öyle söylemiş olmasıdır.

```bash
go install golang.org/dl/go1.27rc3@latest
go1.27rc3 download
```

## 1. Dil Değişti (Evet, Gerçekten)

### 1.1. Genel Metotlar

Go 1.18 ile birlikte genericlerimiz var ve Go 1.18 ile birlikte "Konuşma" da var. Şöyle ilerler:

> "Bir `Map` metodunu slice tipime yazayım bari..."
>
> `method must have no type parameters`
>
> "...tamam. O zaman paket düzeyinde bir fonksiyon olsun."

Metotlar yalnızca _alıcı_ (receiver) tarafından bildirilen tip parametrelerini kullanabiliyordu. Kendi metotlarınız yeni tip parametreleri tanımlayamıyordu. Bu yüzden her generic dönüşüm paket kapsamına sürgün ediliyordu; orada, `MapSlice` adının bir varyasyonunu taşıyan on yedi başka serbest yardımcı fonksiyonun yanında duruyordu.

Go 1.27 bunu düzeltiyor:

```go
type List[E any] []E

// F, metodun kendisi tarafından bildirilen bir tip parametresidir
func (l List[E]) Apply[F any](f func(E) F) List[F] {
	r := make(List[F], len(l))
	for i, x := range l {
		r[i] = f(x)
	}
	return r
}

func main() {
	l := List[int]{1, 2, 3}
	fmt.Println(l.Apply(func(i int) string { return fmt.Sprint(i * 10) }))
	// [10 20 30]
}
```

Alıcının generic olması bile gerekmiyor. Sıradan bir struct da generic bir metoda sahip olabilir:

```go
type Bag struct{ items []any }

func (b *Bag) Add[T any](v T) { b.items = append(b.items, v) }
```

Şimdi, bu öğleden sonra tüm kod tabanınızı yeniden düzenlemeye başlamadan önce, görünüşünden daha önemli olan **iki kısıtlama** var:

1. Arayüz metotları tip parametresi bildiremez.
2. Generic metotlar arayüz metotlarını uygulayamaz.

Sizi ısıracak olan ikincisi:

```go
type Adder interface{ Add(int) int }

type G struct{}

func (G) Add[T any](v T) T { return v }

var _ Adder = G{}
```

```
cannot use G{} (value of struct type G) as Adder value in variable declaration:
	G does not implement Adder (wrong type for method Add)
		have Add[T any](T) T
		want Add(int) int
```

Yani generic metotlar ile dinamik dispatch bir arada kullanılamaz. Bu, Go ekibinin cimri davranması değil: generic bir metodun sonsuz sayıda örneklemesi (instantiation) vardır, oysa bir arayüz metot tablosunun sonlu ve derleme zamanında bilinen olması gerekir. Sonsuz bir şeyi sonlu bir tabloya koyamazsınız. Evren hayır dedi.

Pratik sonuç: generic metotlar, yardımcı nitelikte API'lere sahip somut tipler içindir. Bir arayüzün arkasına saklanması gereken her şey hâlâ eski yaklaşıma ihtiyaç duyar.

Standart kütüphane bundan zaten yararlandı. `math/rand/v2` paketindeki `Rand` bir generic metot kazandı:

```go
func (r *Rand) N[Int intType](n Int) Int
```

```go
r := rand.New(rand.NewPCG(1, 2))
fmt.Println(r.N(int32(100)))     // 76
fmt.Println(r.N(time.Second))    // 616.436223ms
```

Daha önce yalnızca paket düzeyindeki `rand.N` generic'ti, bu da global kaynağı kullanmak anlamına geliyordu. Artık kendi tohumlanmış `*Rand` değeriniz de aynı kolaylığa sahip. Küçük bir şey. Güzel bir şey.

### 1.2. Struct Literal Alan Seçicileri ya da: Issue #9859 Nihayet Huzur Buldu

Gömme (embedding), `u.ID` yazmanıza olanak tanır. Gömme, `User{ID: 1}` yazmanıza olanak _tanımaz_. Bunun yerine `User{Base: Base{ID: 1}}` yazmanızı ister; bu da Go'nun bunu gerçekten kastedip etmediğinizi sormanın yoludur.

[Issue #9859](https://go.dev/issue/9859) 2015 yılında açıldı. Şimdi kapatıldı. Bir yerlerde, o zamandan beri iki kez kariyer değiştirmiş bir gopher, bir GitHub bildirimi alıyordur.

```go
type Object struct{ name, color string }
type Point3D struct {
	Object
	x, y, z float64
}
type Line struct {
	Object
	p, q Point3D
}

// Go 1.27: yükseltilmiş alanı doğrudan kullanın
line := Line{name: "diagonal", q: Point3D{y: -4, z: 12.3}}
```

`name`, `Line` yapısının bir alanı değildir. Gömülü `Object` yapısının bir alanıdır. Daha önce `Line{Object: Object{name: "diagonal"}, ...}` yazmanız gerekiyordu.

Şimdi ayrıntılara gelelim; bunların tamamını gerçekten derlemeyi deneyerek kontrol ettim.

**(a) Anahtar hâlâ düz bir tanımlayıcıdır.** Keyfi bir seçici yolu yazamazsınız.

```go
_ = Line{Object.name: "x"}   // invalid field name Object.name in struct literal
_ = Line{p.x: 1}             // invalid field name p.x in struct literal
```

Yani özellik "anahtarlar artık alan erişimi gibi çalışıyor" değildir. Özellik özellikle "dolaylı olarak yükseltilmiş alan adlarına izin verilmesidir." Başlığın ima ettiğinden biraz daha dar.

**(b) Gömülü bir alanı ve ondan yükseltilmiş bir alanı aynı anda belirtemezsiniz.**

```go
obj := Object{"edge", "black"}
_ = Line{Object: obj, name: "diagonal"}
// cannot specify promoted field name and enclosing embedded field Object
```

Makul. Aynı bellek alanı hakkında birbiriyle çelişen iki şey söylediniz ve derleyici tahmin yürütmeyi reddetti.

**(c) İşaretçi gömmesi teşvik edilmiyor.**

```go
type PtrEmbed struct {
	*Object
	z int
}

_ = PtrEmbed{name: "x"}
// invalid implicit pointer indirection to reach name
```

Bir işaretçiyi takip etmek için takip edilecek bir işaretçiye ihtiyacınız var, ve literal oluşturulurken henüz böyle bir işaretçi yoktur. Bu da haklı bir durum.

İyi haber: `go fix` eski literal'lerinizi sizin için yeniden yazacak. Bunun hakkında daha sonra daha fazla bilgi var.

### 1.3. Fonksiyon Tip Çıkarımı Daha Az Keyfi Hale Geldi

Generic fonksiyonlar için tip çıkarımı bazı yerlerde çalışır, bazı yerlerde çalışmazdı; hangisinin hangisi olduğunun ardında anlaşılabilir bir ilke yoktu. Bir değişkene atama mı? Sorun yok. Tamamen aynı fonksiyonu bir struct alanına koymak mı? Derleyici hatası, lütfen `double[int]` yazın, sanki 2022'deymiş gibi.

Go 1.27, hedef tipin açıkça bilindiği **her bağlamda** çıkarımın çalışmasını sağlıyor:

```go
func double[T ~int | ~float64](v T) T { return v * 2 }

type S struct{ f func(int) int }
type A [1]func(int) int

func main() {
	s := S{f: double}          // 1.26: double[int] yazmak gerekiyordu
	a := A{double}             // 1.26: double[int] yazmak gerekiyordu

	c := make(chan func(int) int, 1)
	c <- double                // 1.26: double[int] yazmak gerekiyordu

	var fn func(float64) float64 = double  // bu her zaman çalışıyordu

	fmt.Println(s.f(21), a[0](5), (<-c)(7), fn(1.5))
	// 42 10 14 3
}
```

Tek bir `double`, üç yerde `func(int) int` olarak, dördüncü yerde `func(float64) float64` olarak örneklenir ve bunların tamamı bağlamdan çıkarılır. Fonksiyon değerleriyle dolu seçenek struct'ları veya handler tabloları yazıyorsanız, kod tabanınızdaki bir sürü `[T]` gürültüsü kaybolmak üzere.

## 2. Çalışma Zamanı: Bedava Performans ve Bir Sızıntı Dedektörü

### 2.1. Boyuta Özel Bellek Ayırma

Derleyici artık küçük nesneler için boyuta özel bellek ayırma rutinlerini çağırıyor. Sürüm notları, 80 bayttan küçük ayırmalarda %30'a varan, bellek ayırma yoğun programlarda ise genel olarak yaklaşık %1'lik bir kazanç iddia ediyor.

Ölçmeden sürüm notlarına inanmıyorum, bu yüzden:

```go
type small struct{ a, b, c, d int }

var sink any

func BenchmarkAlloc(b *testing.B) {
	for b.Loop() {
		sink = &small{}
	}
}

func BenchmarkSlice(b *testing.B) {
	for b.Loop() {
		sink = make([]byte, 48)
	}
}
```

```
# default (size-specialized malloc on)
BenchmarkAlloc-12     3000000     5.358 ns/op
BenchmarkSlice-12     3000000    13.58 ns/op

# GOEXPERIMENT=nosizespecializedmalloc
BenchmarkAlloc-12     3000000     8.722 ns/op
BenchmarkSlice-12     3000000    20.81 ns/op

```

Apple Silicon üzerinde yalnızca bellek ayıran bir mikro benchmark'ta %30–35 daha hızlı. Yani bu en iyi durum: sayıyı iyi göstermek için tasarlanmış bir benchmark tarafından laboratuvar koşullarında elde edildi. Gerçek bir programda GC ve gerçek iş yükü bunun çoğunu gömecektir. Dikkate alınması gereken dürüst iddia yaklaşık %1'lik olanıdır.

Maliyet ikili dosya boyutudur. Hello World:

```
2413202 bytes  (default)
2361826 bytes  (nosizespecializedmalloc)
```

Programınızdan bağımsız olarak sabit yaklaşık 50KB. `GOEXPERIMENT=nosizespecializedmalloc` ile bu özelliği devre dışı bırakabilirsiniz, ancak **bu kaçış yolunun Go 1.28'de kaldırılması planlanıyor**, bu yüzden onu bir yaşam tarzı değil, hata raporu için geçici bir çözüm olarak görün.

### 2.2. Goroutine Sızıntı Profili Artık Gerçek

Go 1.26'da deneyseldi, 1.27'de genel kullanıma sunuldu. `goroutineleakprofile` GOEXPERIMENT'i kalktı; artık sadece çalışıyor.

```go
func leak() {
	ch := make(chan int) // kimse asla gönderim yapmayacak. kimse.
	go func() {
		<-ch
	}()
}

func main() {
	for range 3 {
		leak()
	}
	runtime.GC()
	runtime.GC()
	pprof.Lookup("goroutineleak").WriteTo(os.Stdout, 1)
}
```

```
goroutineleak profile: total 3
3 @ 0x104de3f18 0x104d7f0b0 0x104d7ec34 0x104e374f4 0x104dea024
#	0x104e374f3	main.leak.func1+0x23	/tmp/go127/leak/main.go:12
```

Üç goroutine, kalıcı olarak takılmış, tam olarak bunu nerede yaptığınızı gösteren bir dosya ve satır numarasıyla.

Bunun arkasındaki numara gerçekten zekice: **çöp toplayıcının erişilebilirlik analizini yeniden kullanıyor**. Eğer goroutine G, P ilkelinde bloke olmuşsa ve P, çalıştırılabilir herhangi bir goroutine'den (ya da bu goroutine'lerin uyandırabileceği herhangi bir şeyden) erişilemezse, P'ye hiçbir şey bir daha dokunamaz, dolayısıyla G asla uyanmaz. Bu bir sezgisel değil, bir ispattır.

Aynı tasarım sınırlamayı da bedavaya verir: kanal veya mutex bir global üzerinden veya hâlâ çalışan bir goroutine'in yerel bir değişkeni üzerinden erişilebilirse, GC onu hâlâ görebilir ve çalışma zamanı hiçbir sonuca varamaz. Yukarıdaki basit örneğin bile raporlamak için iki `runtime.GC()` çağrısına ihtiyaç duyduğuna dikkat edin. Her şeyi yakalamaz.

Yine de klasik "context'i iptal etmeyi unuttum, worker goroutine sonsuza kadar yaşıyor" hatasını yakalar; ki çoğu zaman sızıntıların çoğu budur.

`net/http/pprof` paketini içe aktarırsanız, bu profil `/debug/pprof/goroutineleak` adresinde de bulunur. Bunu staging ortamına bağlayın, haftada bir kontrol edin ve sessizce dehşete kapılın.

Bu çalışma Uber'den Vlad Saioc tarafından katkıda bulunuldu; kendilerine seçecekleri bir içecek hak ediyorlar.

### 2.3. Geri İzlemeler Artık Hangi İsteğin Öldüğünü Söylüyor

Go 1.27 veya üstünü bildiren modüller için, geri izleme (traceback) başlık satırları artık `runtime/pprof` goroutine etiketlerini içeriyor.

```go
func handle(ctx context.Context) {
	var wg sync.WaitGroup
	wg.Go(func() {
		buf := make([]byte, 4<<10)
		os.Stdout.Write(buf[:runtime.Stack(buf, true)])
	})
	wg.Wait()
}

func main() {
	labels := pprof.Labels("request", "GET /orders/42", "tenant", "acme")
	pprof.Do(context.Background(), labels, handle)
}
```

```
goroutine 3 [running] {request: "GET /orders/42", tenant: acme}:
main.handle.func1()
	/tmp/go127/tblabel/main.go:15 +0x40
sync.(*WaitGroup).Go.func1()
	...
goroutine 1 [sync.WaitGroup.Wait] {request: "GET /orders/42", tenant: acme}:
...
```

Önemli ayrıntı: **etiketler alt goroutine'lere devredilir.** Goroutine 3 hiç etiket ayarlamadı. Bunu üst goroutine'den aldı.

Yani bir dahaki sefere üretimde bir deadlock yaşandığında ve biri süreci SIGQUIT ile durdurduğunda, hepsi birbirinin aynısı görünen 4.000 goroutine yerine, hangi isteğe ve hangi kiracıya ait olduklarını gösteren etiketlere sahip 4.000 goroutine elde edersiniz. İstek giriş noktanızda üç satırlık `pprof.Do` bunu size sağlar.

Etiketler stderr'e dökmek istemeyeceğiniz şeyler içerebileceğinden, `GODEBUG=tracebacklabels=0` bu özelliği kapatır ve bu devre dışı bırakma seçeneğinin sonsuza dek kalması açıkça amaçlanmıştır.

### 2.4. asynctimerchan Artık Tamamen Gitti

Go 1.23, zamanlayıcı kanallarını tamponsuz (senkron) hale getirdi ve eski davranışa dönmek için `asynctimerchan=1` seçeneğini sundu. 1.27'de bu ayar **kalıcı olarak kaldırıldı**. `time` paketinin kanalları senkrondur, kesinlikle, pazarlık yok.

Buna paralel olarak tanıtılan politika ilginç. `go.mod` dosyanızda kalmış kaldırılmış bir GODEBUG, derlemeyi otomatik olarak bozmaz; yalnızca **eski** değerine ayarlanmışsa bozar:

```
# go.mod contains: godebug asynctimerchan=1
go: error loading go.mod:
go.mod:5: removed GODEBUG "asynctimerchan" set to old value "1" (https://go.dev/doc/godebug#go-127)

# go.mod contains: godebug asynctimerchan=0
(builds fine)
```

Bu, azarlanan tek kişilerin, kaldırılan davranışa gerçekten güvenen kişiler olduğu anlamına gelir. Ayarı nihai varsayılan değerine çekip unutanlar, bunu düşünmeye devam etmeme özgürlüğünü korur. Bu, düşünceli bir API arkeolojisi örneği.

## 3. Standart Kütüphane

### 3.1. encoding/json/v2: Motor Uçuş Sırasında Değiştirildi

Bu büyük olanı. [İki yılı aşkın öneri tartışması](https://go.dev/issue/71497) nihayet sonuçlandı.

Artık **üç paket** var ve bu ayrımı anlamak savaşın büyük kısmı:

| Paket                    | Görevi                                                                         |
| ------------------------ | ------------------------------------------------------------------------------ |
| `encoding/json`          | Bildiğiniz v1 API'si. **Davranış %100 değişmedi.** Artık v2 üzerinde uygulanıyor |
| `encoding/json/v2`       | Anlamsal işleme. Go değerleri ↔ JSON                                           |
| `encoding/json/jsontext` | Sözdizimsel işleme. JSON bir token akışı olarak                                |

Ana nokta, `encoding/json`'un tamamen farklı bir uygulama üzerine yeniden inşa edilmiş olması ve **aynı şekilde davranmasıdır**. İşte nasıl:

```go
// Go 1.27'deki encoding/json.Unmarshal, kısaltılmış
func Unmarshal(data []byte, v any) error {
	return jsonv2.Unmarshal(data, v, DefaultOptionsV1())
}
```

Her eski v1 tuhaflığı bir seçenek olarak kodlandı, `DefaultOptionsV1()` içinde paketlendi ve v1 API'si bu paketi her zaman uygular. Bu da aşağıdakinin 1.26 ve 1.27'de aynı davrandığı anlamına gelir:

```go
var m map[string]int
json.Unmarshal([]byte(`{"a":1,"a":2}`), &m)  // <nil>, map[a:2]
```

Evet, v1 hâlâ yinelenen anahtarları sessizce kabul eder ve sonuncusunu alır. Her zaman böyleydi. Hâlâ öyle. Uyumluluk, kötü kısımlarla da uyumluluk demektir.

**Buna karşılık v2'nin görüşleri var:**

```go
var m map[string]int
jsonv2.Unmarshal([]byte(`{"a":1,"a":2}`), &m)
// jsontext: duplicate object member name "a"

var s string
jsonv2.Unmarshal([]byte("\"\xff\""), &s)
// jsontext: invalid UTF-8 after offset 1
```

Yinelenen anahtarlar ve geçersiz UTF-8 reddedilir. Her ikisi de sadece dağınık olmakla kalmayıp gerçekten tehlikelidir; iki ayrıştırıcı hangi yinelenen anahtarın kazandığı konusunda anlaşamadığında güvenlik açıkları ortaya çıkar. CouchDB'nin CVE-2017-12635 açığı tam olarak buydu: iki `roles` anahtarı içeren bir JSON gövdesinde, doğrulayıcı birini okudu, depolama katmanı diğerini okudu. Reddetmek doğru karar.

Seçenekler değişkendir (variadic):

```go
type Config struct {
	Name    string   `json:"name"`
	Tags    []string `json:"tags,omitzero"`
	Timeout int      `json:"timeout,omitzero"`
}

out, _ := jsonv2.Marshal(Config{Name: "api"})
// {"name":"api"}

// sıralanmış map anahtarları + girinti
out, _ = jsonv2.Marshal(map[string]int{"b": 2, "a": 1},
	jsonv2.Deterministic(true), jsontext.WithIndent("  "))
// {
//   "a": 1,
//   "b": 2
// }

// bilinmeyen alanları reddet — daha önce bir Decoder ve DisallowUnknownFields() gerekiyordu
var c Config
err := jsonv2.Unmarshal([]byte(`{"name":"api","nope":1}`), &c,
	jsonv2.RejectUnknownMembers(true))
// json: cannot unmarshal JSON string into Go main.Config:
//   unknown object member name "nope"
```

`Deterministic`, `MatchCaseInsensitiveNames`, `StringifyNumbers`, `FormatNilSliceAsNull`, `OmitZeroStructFields`: daha önce üçüncü taraf bir kütüphaneyle ya da elle yazılmış bir `MarshalJSON` ile çözdüğünüz şeylerin çoğu artık bayraklar.

Ve geçiş hikâyesi en iyi kısmı. **Sonraki seçenekler kazanır**, bu yüzden v2'nin katılığını bir seferde bir davranış olarak benimseyebilirsiniz:

```go
// v1 semantiğini koru, ama v2'nin yaptığı gibi yinelenen anahtarları reddet
jsonv2.Unmarshal(data, &v,
	json.DefaultOptionsV1(),
	jsontext.AllowDuplicateNames(false))
// duplicate object member name
```

Yinelenen anahtarları kabul etmeyi bırakmak için 200 bin satırlık bir kod tabanını v2'ye taşımanız gerekmez. Tek bir seçeneği değiştirirsiniz. Büyük projelerde bu gerçekçi yoldur.

Performans: marshal işlemi hemen hemen eşit, **unmarshal işlemi ise önemli ölçüde daha hızlı.** Bir sorun olursa, `GOEXPERIMENT=nojsonv2` eski uygulamayı geri getirir; ama bu kaçış yolu da sonunda kaldırılacak, bu yüzden buna alışmak yerine bir issue açın.

`jsontext` düşük seviyeli katmandır: JSON'u `Token` ve `Value` olarak gezen, sizi dürüst tutan bir durum makinesiyle çalışan `Encoder`/`Decoder` bileşenleridir. Akışkan bir dönüştürücü ya da JSON filtresi yazıyorsanız ve Go değerlerini hiç somutlaştırmak istemiyorsanız buna başvurun.

### 3.2. Standart uuid Paketi

Sonunda. RFC 9562, standart kütüphanede, `go get` gerektirmeden.

```go
import "uuid"

func main() {
	fmt.Println(uuid.NewV4())
	// b97aa695-da08-472c-af81-ff088129019f

	// v7: ilk 48 bit bir zaman damgasıdır, bu yüzden bunlar her zaman oluşturulma sırasına göre sıralanır
	a, b := uuid.NewV7(), uuid.NewV7()
	fmt.Println(a.Compare(b) < 0) // true

	u, err := uuid.Parse("urn:uuid:0198a1b2-c3d4-7e5f-8a9b-0c1d2e3f4a5b")
	fmt.Println(u, err)
	// 0198a1b2-c3d4-7e5f-8a9b-0c1d2e3f4a5b <nil>

	fmt.Println(uuid.Nil(), uuid.Max())
	// 00000000-0000-0000-0000-000000000000 ffffffff-ffff-ffff-ffff-ffffffffffff
}
```

Tüm API şunlardan oluşuyor: `New`, `NewV4`, `NewV7`, `Nil`, `Max`, `Parse`, `MustParse` ve tek bir tip: `type UUID [16]byte`. Bu kadar. Kahveniz soğurken tüm paket belgelerini okuyabilirsiniz.

Bilmeye değer ayrıntılar:

- **`UUID`, `[16]byte` tipindedir**, bu yüzden `==` çalışır ve doğrudan bir map anahtarı olarak kullanılabilir. `google/uuid` ile aynı tasarım.
- **`Nil` ve `Max` değişken değil, fonksiyondur.** Çünkü paket düzeyinde bir `var Nil UUID` ayağınıza doğrultulmuş yüklü bir silahtır ve birileri bir gün ona atama yapacaktır.
- Rastgele bitler **kriptografik olarak güvenli** bir üreteçten gelir.
- `encoding.TextMarshaler`/`TextUnmarshaler`/`TextAppender` arayüzlerini uygular, bu yüzden JSON struct'larına doğrudan oturur.
- **Veritabanı birincil anahtarları için istediğiniz `NewV7`'dir.** Zamana göre sıralı olması, B-ağacı indeksinizin parçalanmasını durdurur; v4 UUID'lerin bu konuda bilinen şekilde kötü olduğu bir durumdur.

Artık bir bağımlılığı silebilirsiniz. v1/v3/v5 ya da daha gelişmiş ayrıştırma seçeneklerine ihtiyacınız varsa, üçüncü taraf kütüphanelerin hâlâ bir işi var.

### 3.3. crypto/mldsa: Kuantum Sonrası İmzalar ve Bunlar Çok Büyük

Go 1.24, kuantum sonrası anahtar değişimi için `crypto/mlkem` paketini verdi. Go 1.27 diğer yarısını getiriyor: FIPS 204 olarak standartlaştırılmış ML-DSA imzaları.

```go
sk, _ := mldsa.GenerateKey(mldsa.MLDSA65())
pk := sk.PublicKey()

msg := []byte("release the gophers")
opts := &mldsa.Options{Context: "gosuda.org/blog"}

sig, _ := sk.Sign(rand.Reader, msg, opts)

fmt.Println("private key seed:", len(sk.Bytes()), "bytes")  // 32
fmt.Println("public key:", len(pk.Bytes()), "bytes")        // 1952
fmt.Println("signature:", len(sig), "bytes")                // 3309

fmt.Println(mldsa.Verify(pk, msg, sig, opts))
// <nil>
fmt.Println(mldsa.Verify(pk, msg, sig, &mldsa.Options{Context: "other"}))
// mldsa: invalid signature
```

Bu sayılara bakın. **Tek bir imza 3.309 bayttır.** Ed25519 ise 64 bayttır. Bu 50 kat bir artış demek ve açık anahtar bunun üzerine neredeyse 2KB ekliyor. Bunlardan birkaçını bir sertifika zincirine yerleştirirseniz, TLS el sıkışmanız kendi MTU stratejisine ihtiyaç duymaya başlar.

Bu, bugün kuantum direncinin gerçek maliyeti ve herkesin yarın her şeyi değiştirmemesinin nedeni. Ama artık standart kütüphanede, ve ihtiyaç duymadan _önce_ orada olması gereken yer burası.

`Options.Context` alan ayrımıdır: aynı anahtarla farklı amaçlar için imzalayın, her biri için farklı bir context kullanın ve bir context'teki imza diğerinde doğrulanmaz. Yukarıdaki örnek tam olarak bunu gösteriyor: aynı anahtar, aynı mesaj, farklı context, reddedildi.

`PrivateKey`, `crypto.Signer` arayüzünü uygular, bu yüzden mevcut arayüzlere uyar. `crypto/x509` ML-DSA anahtarlarını ve imzalarını işler, `crypto/tls` ise TLS 1.3'te `MLDSA44`/`MLDSA65`/`MLDSA87` imza şemalarını destekler.

Ayrıca rastgeleliği atlayan `SignDeterministic` de var; testler ve yeniden üretilebilir derlemeler için kullanışlı.

### 3.4. simd: Assembly Olmadan Vektör Komutları

Go 1.26, mimariye özgü `simd/archsimd` paketini deney olarak tanıttı. Go 1.27 `simd` paketini ekliyor: **taşınabilir ve vektör genişliğinden bağımsız**. `GOEXPERIMENT=simd` ile etkinleştirin.

```go
// dst = a*x + y
func axpy(dst, x, y []float32, a float32) {
	va := simd.BroadcastFloat32s(a)
	w := va.Len()

	i := 0
	for ; i+w <= len(x); i += w {
		vx := simd.LoadFloat32s(x[i:])
		vy := simd.LoadFloat32s(y[i:])
		vx.MulAdd(va, vy).Store(dst[i:])
	}
	// kuyruğu kısmi yükleme/saklama ile işle — skaler temizleme döngüsü yok
	if i < len(x) {
		vx, _ := simd.LoadFloat32sPart(x[i:])
		vy, _ := simd.LoadFloat32sPart(y[i:])
		vx.MulAdd(va, vy).StorePart(dst[i:])
	}
}
```

```bash
$ GOEXPERIMENT=simd go1.27rc3 run ./simddemo
vector bits: 128 emulated: false
[4 7 10 13 16 19 22 25 28 31]
```

Önemli olan tasarım seçimi: **vektör genişliği asla sabit kodlanmaz.** Çalışma zamanında `va.Len()` sorarsınız. `VectorBitSize()` gerçek genişliği söyler, `Emulated()` ise gerçek donanım mı yoksa kibar bir yazılım taklidi mi aldığınızı söyler. Benim Mac'im 128 bitlik NEON bildirdi; bir AVX-512 makinesi daha fazla bildirir; hiçbir şeyi olmayan bir makine ise emülasyon bildirir ve kod yine de çalışır.

`LoadFloat32sPart`/`StorePart` özel bir değinmeyi hak ediyor. El yazımı SIMD'nin en can sıkıcı kısmı her zaman dizinin sonundaki düzensiz kuyruktur ve bu, ayrı bir skaler döngüye ihtiyaç duymadan bunu çözer.

Hâlâ deneysel, API hâlâ kararsız, üretime koymayın. Ama bunun assembly ya da cgo değil de Go kodu olması gerçekten büyük bir olay.

### 3.5. hash/maphash.Hasher

Bir değer tipi ile hash tabanlı konteynerler arasındaki sözleşmeyi tanımlayan yeni bir arayüz:

```go
type Hasher[T any] interface {
	Hash(*Hash, T)
	Equal(x, y T) bool
}
```

Neden? Go'nun yerleşik map'i yalnızca `comparable` anahtarları kabul eder. Bir slice üzerine anahtar koyamazsınız. "Büyük/küçük harf duyarsız eşitlik" tanımlayamazsınız. `Hasher` her ikisini birden çözer:

```go
type CaseInsensitive struct{}

func (CaseInsensitive) Hash(h *maphash.Hash, s string) {
	h.WriteString(strings.ToLower(s))
}
func (CaseInsensitive) Equal(x, y string) bool {
	return strings.ToLower(x) == strings.ToLower(y)
}

var seed = maphash.MakeSeed()

func hashOf[T any](hr maphash.Hasher[T], v T) uint64 {
	var h maphash.Hash
	h.SetSeed(seed)   // aynı tohum, yoksa bunların hiçbirinin bir anlamı yok
	hr.Hash(&h, v)
	return h.Sum64()
}

fmt.Println(hashOf(CaseInsensitive{}, "Go") == hashOf(CaseInsensitive{}, "GO"))
// true
```

Sıradan `==` semantiği için `ComparableHasher[T]` vardır:

```go
hashOf(maphash.ComparableHasher[int]{}, 42)
```

Tuzak şu: **`Hasher` bir arayüzdür, bir veri yapısı değildir.** Onu tüketen standart bir hash tablosu ya da Bloom filtresi henüz yok. Bu, gelecekteki bir konteyner paketi için zemin hazırlığı. Bugün, kendi yapınızı oluştururken ya da `types.Type` değerini bir map anahtarı olarak kullanmanıza (ve `Identical` ilişkisine uymanıza) izin veren `go/types.Hasher` gibi mevcut bir uygulamayı tüketirken kullanırsınız.

Tohum yönetimi size kalmış. Yukarıdaki `hashOf` her çağrıda yeni bir tohum üretseydi, aynı değerler farklı hashlenirdi ve örnek `false` yazdırırdı; ki ilk denemem de tam olarak bu hataydı. Konteyner başına bir tohum. (Tohum, hash-flooding DoS saldırılarını engellemek için rastgele seçilir; bu yüzden sabit bir değer değildir.)

### 3.6. httptest.NewTestServer + synctest.Sleep: Uyuyan Adam Vurdu

Bu sürümden yalnızca bir şey benimseyecekseniz, bu olsun.

`testing/synctest`, Go 1.25'te genel kullanıma geçti ve eşzamanlı kod testleri için sahte bir saat sağladı. Ancak testiniz gerçek bir ağa dokunduğu an illüzyon çöküyordu. Go 1.27'nin `httptest.NewTestServer` fonksiyonu **bellek içi sahte bir ağ** kullanır, bu yüzden balon bozulmadan kalır. Ve `synctest.Sleep` (= `time.Sleep` + `synctest.Wait`) tabloyu tamamlar.

İşte üstel geri çekilmeli (exponential backoff) yeniden deneme testi:

```go
func TestRetryWithBackoff(t *testing.T) {
	synctest.Test(t, func(t *testing.T) {
		var hits int
		srv := httptest.NewTestServer(t, http.HandlerFunc(
			func(w http.ResponseWriter, r *http.Request) {
				hits++
				if hits < 3 {
					w.WriteHeader(http.StatusServiceUnavailable)
					return
				}
				io.WriteString(w, "ok")
			}))

		client := srv.Client()
		start := time.Now()
		var body string
		for attempt := range 5 {
			resp, err := client.Get(srv.URL)
			if err != nil {
				t.Fatal(err)
			}
			b, _ := io.ReadAll(resp.Body)
			resp.Body.Close()
			if resp.StatusCode == http.StatusOK {
				body = string(b)
				break
			}
			synctest.Sleep(time.Duration(1<<attempt) * time.Second)
		}

		if body != "ok" {
			t.Fatalf("got %q", body)
		}
		// geri çekilme tam olarak 1s + 2s = 3s olmalı
		if elapsed := time.Since(start); elapsed != 3*time.Second {
			t.Fatalf("elapsed = %v, want 3s", elapsed)
		}
		t.Logf("hits=%d elapsed=%v", hits, time.Since(start))
	})
}
```

```
=== RUN   TestRetryWithBackoff
    x_test.go:48: hits=3 elapsed=3s
--- PASS: TestRetryWithBackoff (0.00s)
```

Bunu iki kez okuyun. Gerçek bir HTTP sunucusuna karşı üç saniyelik geri çekilmeyi simüle etti ve **0.00 saniyede** bitirdi. Ve doğrulama `elapsed == 3*time.Second` şeklinde: _tam olarak_ üç saniye, "en az üç saniye, zamanlayıcı gecikmesi dahil" değil. Sahte saatler titremez.

`synctest.Sleep` belirli bir nedenle var: testiniz, test edilen kodla aynı süre kadar uyursa, hangisinin önce uyanacağı tahmin yürütmeye kalır. `synctest.Sleep` uyur _ve sonra_ balondaki diğer tüm goroutine'ler kalıcı olarak bloke olana kadar bekler, böylece sistemi yerleştikten sonra gözlemlersiniz.

Zaman aşımları, yeniden denemeler, devre kesiciler, hız sınırlayıcılar: zamana bağlı her HTTP istemci testi hızlı ve deterministik hale gelebilir. Test paketiniz şu anda `time.Sleep(100 * time.Millisecond)` ve umutla bir arada tutuluyorsa, bu sizin çıkışınızdır.

### 3.7. Üretimi Gerçekten Etkileyen net/http Değişiklikleri

Sessiz, ama metriklerinizde görünecekler.

**HTTP/1 yanıt gövdeleri Close üzerinde otomatik olarak boşaltılır.** Okunmamış içerik, gövdeyi kapattığınızda (muhafazakâr bir sınıra kadar) boşaltılır, böylece bağlantı yeniden kullanılabilir. Bu da 2016'dan beri herkesin aynı Stack Overflow cevabından kopyalayıp yapıştırdığı bu büyüyü artık silebileceğiniz anlamına gelir:

```go
// artık gerekli değil
defer func() {
	io.Copy(io.Discard, resp.Body)
	resp.Body.Close()
}()
```

Çoğu program için bu ya bir işlem yapmaz ya da küçük bir kazançtır. Eğer işleri _kötüleştiriyorsa_, muhtemelen sürüm notlarının nazikçe tarif ettiği kategoridesiniz: `Transport.MaxIdleConns` 0 olarak ayarlanmış ya da her istek için yeni bir `Client`, bu da boşta bağlantı sınırını tamamen atlatıyor. `Transport.DisableKeepAlives = true` bunu örtbas eder, ama sürüm notlarının asıl tavsiyesi "daha derin bir inceleme muhtemelen faydalı olacaktır" şeklinde, ki bu Go ekibinin dilinde _daha büyük sorunlarınız var_ demektir.

**HTTP/2 istemci önceliği (RFC 9218).** Sunucu artık istemcinin öncelik sinyallerine uyar. Eski round-robin zamanlamayı tercih ettiyseniz, `Server.DisableClientPriority = true`.

**`Server.MaxHeaderValueCount`.** Sunucunun kabul edeceği başlık değeri sayısını sınırlar, varsayılanı `DefaultMaxHeaderValueCount`'tır. "On bin başlık gönder ve ne olacağını izle" yönteminin kapısına bir kapı daha kapatıldı.

**Kullanıcı tarafından sağlanan bağlantılarda ALPN.** `net.Conn` değeriniz `ConnectionState() tls.ConnectionState` metodunu uyguluyorsa, `Transport` ve `Server` bu bağlantı üzerinde TLS ALPN müzakeresi yapar; böylece bir proxy üzerinden geçen özel dialer'lar yine de HTTP/2'yi müzakere edebilir.

### 3.8. Keyif Veren Küçük Şeyler

**`strings.CutLast` / `bytes.CutLast`.** `Cut`, ayırıcının _ilk_ geçtiği yerden böler. "Son" varyantı yoktu, bu yüzden herkes `LastIndex` ve dilimlemeyi elle yazıyordu ve bizim yaklaşık %30'umuz ilk denemede bir off-by-one hatası yaptı.

```go
name, ext, ok := strings.CutLast("archive.tar.gz", ".")
// archive.tar gz true
```

Dosya uzantıları ve `host:port` ayrıştırmak için harika; burada _son_ iki nokta üst üste işaretini bulmanız gerekir, çünkü IPv6 adresleri bunlarla doludur.

**`math/big.Int.Divide`.** Açık bir yuvarlama moduyla bölme; "`Quo` mu `Div` mi istiyorum?" yazı tura atışının yerini alıyor:

```go
x, y := big.NewInt(-7), big.NewInt(2)

new(big.Int).Divide(x, y, new(big.Int), big.Trunc)  // q=-3 r=-1
new(big.Int).Divide(x, y, new(big.Int), big.Floor)  // q=-4 r=1
new(big.Int).Divide(x, y, new(big.Int), big.Round)  // q=-4 r=1
new(big.Int).Divide(x, y, new(big.Int), big.Ceil)   // q=-3 r=-1
```

Yuvarlama kuralının bir yönetmelikte yazılı olduğu bir alanda çalışıyorsanız, bu sizin içindir.

**`url.URL.Clone` ve `url.Values.Clone`.** Derin kopyalar. Eski `*u` sığ kopyası `Userinfo` işaretçisini paylaşıyordu ve bu, bulunması bir gün, düzeltilmesi beş saniye sürecek türden bir hataya yol açıyordu.

```go
orig, _ := url.Parse("https://gosuda.org/blog?tag=go&tag=1.27")
clone := orig.Clone()
clone.Host = "example.com"
fmt.Println(orig.Host, clone.Host)  // gosuda.org example.com
```

**`net.UnixConn`** okuma metotları artık `io.EOF` değerini `net.OpError` içine sarmak yerine doğrudan döndürür. `err == io.EOF` artık çalışıyor, her zaman olması gerektiği gibi.

**`database/sql.ConvertAssign` ve `driver.RowsColumnScanner`.** Sürücü geliştiricilerine yönelik özellikler. Birincisi, `Rows.Scan`'in gerçekleştirdiği tip dönüşümlerini açığa çıkarır; ikincisi, sürücülerin ara bir ayırmadan kaçınarak doğrudan kullanıcı hedeflerine tarama yapmasına izin verir.

**`unicode` 15 → 17.** Tek bir sıçrayışta iki sürüm. Dize sınıflandırması ve normalleştirme davranışı ince biçimde değişebilir. Buna bağlı testleriniz varsa, bunu öğreneceksiniz.

**`compress/flate` daha hızlı hale geldi** ve **çıktı baytları Go 1.26'dan farklı olabilir.** Bu etki `archive/zip`, `compress/gzip`, `compress/zlib` ve `image/png` paketlerine de yayılır. Sıkıştırılmış çıktıyı hash'leyen golden-file testleriniz varsa, bunlar bozulacak ve bu bir gerileme olmayacak. Yükseltmeden _önce_ kontrol edin, olay incelemesi sırasında değil.

## 4. Araç Zinciri

### 4.1. go fix Daha Fazla Modernleştiriciye Sahip

`go fix` sessizce bir kod modernleştirme aracına dönüşüyor. Go 1.27 `atomictypes`, `embedlit`, `slicesbackward` ve `unsafefuncs` ekliyor. Önizleme için `-diff` kullanın:

```go
package fixdemo

import (
	"sync"
	"sync/atomic"
)

type Base struct{ ID int }
type User struct {
	Base
	Name string
}

func New() User {
	return User{Base: Base{ID: 1}, Name: "gopher"}
}

var counter int64

func Incr() { atomic.AddInt64(&counter, 1) }

func Reverse(s []string) {
	for i := len(s) - 1; i >= 0; i-- {
		_ = s[i]
	}
}

func Spawn(wg *sync.WaitGroup) {
	wg.Add(1)
	go func() {
		defer wg.Done()
	}()
}
```

```bash
$ go1.27rc3 fix -diff ./fixdemo
```

```diff
 import (
+	"slices"
 	"sync"
 	"sync/atomic"
 )

 func New() User {
-	return User{Base: Base{ID: 1}, Name: "gopher"}
+	return User{ID: 1, Name: "gopher"}
 }

-var counter int64
+var counter atomic.Int64

-func Incr() { atomic.AddInt64(&counter, 1) }
+func Incr() { counter.Add(1) }

 func Reverse(s []string) {
-	for i := len(s) - 1; i >= 0; i-- {
-		_ = s[i]
+	for _, v := range slices.Backward(s) {
+		_ = v
 	}
 }

 func Spawn(wg *sync.WaitGroup) {
-	wg.Add(1)
-	go func() {
-		defer wg.Done()
-	}()
+	wg.Go(func() {
+	})
 }
```

Küçük bir dosyada dört modernleştirici tetiklendi:

- `embedlit`: §1.2'deki yeni sözdizimini kullanarak gömülü literal'leri yeniden yazar
- `atomictypes`: `atomic.AddInt64(&x, 1)`, `atomic.Int64.Add(1)` olur; bu, atomik olmayan erişimi imkânsız kılar ve farkında olmadığınız 32 bitlik hizalama hatalarını sessizce düzeltir
- `slicesbackward`: geriye doğru döngüler `slices.Backward` olur
- `waitgroupgo`: `Add`/`go`/`Done` ritüeli `wg.Go` olur (belirsizliği önlemek için 1.26'daki `waitgroup` adı değiştirildi)

`go tool fix help` 26 modernleştiricinin tamamını listeler; `go tool fix help <name>` birini açıklar. Ayrıca `fmtappendf`, "üslup kaygıları nedeniyle" kaldırıldı; bu, o issue tartışmasında ne olduğunu anlatmanın çok diplomatik bir yoludur.

Eski bir kod tabanında `go fix ./...` çalıştırmak gerçekten tatmin edici bir öğleden sonra. Önce diff'i okuyun, tabii ki.

### 4.2. go test Varsayılan Olarak stdversion Çalıştırır

Bu, gününüzü bölme ihtimali en yüksek değişiklik.

`go test` artık varsayılan olarak `stdversion` vet kontrolünü çalıştırır; bu kontrol, `go.mod` dosyanızdaki `go` yönergesinin izin verdiğinden daha yeni standart kütüphane sembollerini işaretler:

```go
// go.mod says: go 1.24
package sv

import "strings"

func Ext(name string) string {
	_, ext, _ := strings.CutLast(name, ".")  // CutLast is a 1.27 symbol
	return ext
}
```

```
$ go1.27rc3 test ./...
# sv
./x.go:6:23: strings.CutLast requires go1.27 or later (module is go1.24)
FAIL	sv [build failed]
```

Bu, her şeyin sizin makinenizde (en güncel araç zinciriyle) çalıştığı ama CI'da ya da bir kullanıcının daha eski ortamında patladığı klasik hata modunu ortadan kaldırır. Muhafazakâr bir `go` yönergesiyle kütüphane yayınlıyorsanız, bu bir hediye.

### 4.3. go test -json, OutputType Kazandı

`"Action":"output"` satırları artık isteğe bağlı bir `"OutputType"` alanı taşıyor: `"error"`, `"error-continue"` veya `"frame"`.

```
'frame'  '=== RUN   TestFail\n'
None     '    x_test.go:6: hello\n'
'error'  '    x_test.go:7: boom\n'
'frame'  '--- FAIL: TestFail (0.00s)\n'
'frame'  'FAIL\n'
```

`t.Log` çıktısı (alan yok), `t.Error` çıktısı (`error`) ve çerçeve tarafından üretilen satırlar (`frame`) artık ayırt edilebilir. Test çıktısının hangi satırlarının "gerçek" olduğunu anlamak için regex yazmış olan herkes onu artık silebilir.

### 4.4. go doc İyileştirmeleri

**`package@version` sözdizimi.** Modülünüze eklemeden belirli bir sürümün belgelerini okuyun:

```bash
$ go1.27rc3 doc golang.org/x/sync/errgroup@v0.10.0
package errgroup // import "golang.org/x/sync/errgroup"
...
```

Yükseltmeden önce neyin değiştiğini kontrol etmek için kullanışlı.

**`-ex` ve örnek kaynağının yazdırılması:**

```bash
$ go1.27rc3 doc -ex strings | grep Example
    func ExampleClone()
    func ExampleCompare()
    func ExampleContains()
    func ExampleCut()
    func ExampleCutPrefix()
    ...

$ go1.27rc3 doc strings.ExampleCut
package main

import (
	"fmt"
	"strings"
)

func main() {
	show := func(s, sep string) {
		before, after, found := strings.Cut(s, sep)
		fmt.Printf("Cut(%q, %q) = %q, %q, %v\n", s, sep, before, after, found)
	}
	show("Gopher", "Go")
	...
}

Output:
Cut("Gopher", "Go") = "", "pher", true
```

Örnek kaynağı _ve_ beklenen çıktı, gelecek perşembe de açık kalacak bir tarayıcı sekmesini açmadan, terminalde.

### 4.5. go mod tidy require Bloklarınızı Temizler

`go 1.27` veya üstü modüller için `go mod tidy`, dağınık `require` bloklarını en fazla iki bloğa (doğrudan ve dolaylı) birleştirir ve ilişkili yorumları korur.

```go
// Önce
module tidydemo

go 1.27

require golang.org/x/sync v0.10.0

// networking
require golang.org/x/net v0.33.0

require (
	golang.org/x/sys v0.28.0 // indirect
)

require golang.org/x/text v0.21.0 // indirect
```

```go
// Sonra: go mod tidy
module tidydemo

go 1.27

require (
	// networking
	golang.org/x/net v0.33.0
	golang.org/x/sync v0.10.0
)
```

`// networking` yorumunun korunduğuna dikkat edin. Bu, çoğunlukla **Git birleştirme çakışması çözümünden** sonra temizlik yapar; dağınık `require` blokları tam da orada doğar. Ekibinizde bağımlılık ekleyen üçten fazla kişi varsa, `go.mod` çakışmalarınız belirgin biçimde daha sessiz hale gelecek.

### 4.6. Çeşitli Küçük Konular

- **`bzr` desteği kaldırıldı.** Bu sizi etkiliyorsa, hikâyesini gerçekten duymak isterim.
- **`go tool trace -http`, yalnızca bir port verildiğinde localhost'a bağlanır.** `-http=:6060` artık her arayüzde dinlemez. Bunu kastettiyseniz `-http=0.0.0.0:6060` kullanın. Bu, `go tool pprof` ile uyumlu hale gelir ve ara sıra yaşanan kazara herkese açık profilleyici sorununu önler.
- **Yanıt dosyaları (`@file`)**, `compile`, `link`, `asm`, `cgo`, `cover` ve `pack` tarafından GCC uyumlu bir biçimde desteklenir. Komut satırı uzunluk sınırlarını aşan derleme sistemleri için; merhaba, Bazel.

## 5. Derleyici, Bağlayıcı, Portlar

**Derleyici.** `//line` yönergelerindeki göreli dosya adları artık, `go/scanner` ile uyumlu olarak, içeren dosyanın dizinine göre çözümlenir. Kod üreticileri yazıyorsanız ilgilidir.

Fonksiyon literal'i (closure) sembol adları da artık daha basit: inline edilip edilmemesinden bağımsız olarak aynı ad kullanılır ve aynı literal'in birden fazla örneği ikili dosyada kodu paylaşabilir. İşlevsel bir değişiklik yok, _ancak_: fonksiyon kimliğini `reflect.Value.Pointer` ile karşılaştıran kod, daha önce olduğundan daha sık "eşit" görecek. Bu karşılaştırma hiçbir zaman geçerli değildi, ama bunu kullanıyorsanız, artık daha yüksek sesle yalan söylemeye başlayacak.

**Bağlayıcı.** Yeni `-macos` ve `-macsdk` seçenekleri, macOS `LC_BUILD_VERSION` yükleme komutundaki OS ve SDK sürümlerini ayarlar.

**Portlar.**

- **Darwin artık macOS 13 Ventura veya üstünü gerektiriyor**, bu 1.26'da duyurulmuştu. CI runner'larınızı kontrol edin.
- **PowerPC (`GOOS=linux GOARCH=ppc64`) ELFv2 ABI'sine geçti.** Linux çekirdeği 3.13+ gerektirir (RHEL7 3.10'a geriye taşındı). Cgo, PIE ve harici bağlama artık destekleniyor. Cgo kullanıyorsanız ama statik, saf Go bir ikili dosyaya ihtiyacınız varsa, `CGO_ENABLED=0` ayarlayın.

## 6. Yükseltme Kontrol Listesi

Go 1.27 uyumluluğu ciddiye alıyor, ama sürümü yükseltmeden önce şunları kontrol edin:

- [ ] **Sıkıştırılmış çıktı üzerindeki golden-file testleri.** `compress/flate` kodlayıcılarını değiştirdi; gzip/zip/png baytları farklı olabilir.
- [ ] **JSON hata mesajı dizelerini eşleştiren testler.** Davranış aynı; **hata metni aynı değil.**
- [ ] **`go.mod` içindeki kaldırılmış GODEBUG'lar.** `asynctimerchan`, `gotypesalias`, `tlsrsakex`, `tls3des`, `tls10server`, `tlsunsafeekm`, `x509keypairleaf` — bunlar yalnızca _eski_ değerlerine ayarlanmışsa derlemeyi başarısız kılar.
- [ ] **`stdversion` ihlalleri.** `go test` artık bunları yakalıyor. Muhafazakâr bir `go` yönergesi olan bir kütüphaneyi sürdürüyorsanız, erken çalıştırın.
- [ ] **macOS 12 veya daha eski CI runner'ları.** Destek kalktı.
- [ ] **Fonksiyon literal'i sembol adlarına dayanan testler** ve **`reflect.Value.Pointer` fonksiyon karşılaştırmaları.**
- [ ] **`Transport.MaxIdleConns = 0`** ya da her istek için bir `Client`. Otomatik boşaltılan yanıt gövdeleriyle birlikte, bu daha yavaş çalışmaya neden olabilir.

## Kapanış Düşünceleri

Go 1.27, birçok ertelenmiş bakımın aynı anda geldiği sürüm.

Genel metotlar, 1.18 generic çalışmasının eksik parçasıydı. Struct literal alan seçicileri on bir yıllık bir issue'yu kapattı. `encoding/json/v2` iki yıllık bir öneri tartışmasıydı. Ve `uuid`, neredeyse her Go projesinin on yıldır aynı üçüncü taraf bağımlılıkla yamaladığı bir boşluğu doldurdu.

Bu sürümden gerçekten değer elde etmek için bir öncelik sırası istiyorsanız:

1. **`httptest.NewTestServer` + `synctest.Sleep`**: zamana bağlı HTTP testleri hızlı ve deterministik hale gelir. Tüm sürümdeki en iyi çaba-getiri oranı.
2. **Goroutine sızıntı profili**: staging'de bir uç nokta açın ve alçakgönüllü olmaya hazırlanın.
3. **Geri izleme goroutine etiketleri**: istek giriş noktanızda üç satırlık `pprof.Do`, bir sonraki sabah 3'teki yığın dökümünüzü okunabilir bir şeye dönüştürür.
4. **`go fix ./...`**: modernleştirme işini araca bırakın.
5. **`encoding/json/v2`**: acele etmeyin. Bir seferde bir seçenek benimseyin.

`go1.27rc3`'ü alın ve test paketinizi şimdi bununla çalıştırın. Bu kontrol listesindeki her şeyi bir salı öğleden sonrası keşfetmek, bir olay sırasında keşfetmekten çok daha keyifli.

**Kaynakça**

- [Go 1.27 Sürüm Notları](https://go.dev/doc/go1.27)
- [The Go Programming Language Specification](https://go.dev/ref/spec)
- [proposal: encoding/json/v2 (#71497)](https://go.dev/issue/71497)
- [proposal: portable SIMD (#78902)](https://go.dev/issue/78902)
- [proposal: hash/maphash.Hasher (#70471)](https://go.dev/issue/70471)
