Dilimler ve diziler, Go'da en çok kullanılan veri yapılandırmalarındandır. Benzer bir sözdizimine sahip olmalarına rağmen, yapı ve davranışları arasındaki farklar performans, bellek ve semantik hatalara yol açabilir.
Konu Tarihi:
Go, başlangıçtan itibaren açık bir bellek yönetimi modeli seçti, burada diziler (arrays) sabit boyutta bir dizi elemandan oluşurken, dilimler (slices) bir diziye dinamik bir görünüm sağlar. Bu ayrım, işlemlerin maliyetini ve kodun davranışını kontrol etmeyi mümkün kılar.
Sorun:
Ana zorluk, dizi kopyalama (değer semantiği) ve dilimlerin "referans" yapısını karıştırmaktır. Bu türlerin fonksiyonlara geçirilmesi ve değerlerin değiştirilmesi durumunda hatalar sıkça ortaya çıkar, bu da beklenmedik yan etkilerle sonuçlanır.
Çözüm:
Diziler her zaman değer ile geçirilirken kopyalanır: fonksiyon tüm içeriğin bir kopyasını alır. Dilim ise, bir diziye işaretçi, uzunluk (length) ve kapasiteden (capacity) oluşan küçük bir yapıdır. Dizi içindeki değişiklikler dışarıda görülebilir, eğer dizinin içeriği değiştirilirse (ama eğer dilim fonksiyon içinde yeni bir diziye yönlendirilirse, değişiklikler görünmez).
Kod örneği:
func updateArray(arr [3]int) { arr[0] = 10 } func updateSlice(slc []int) { slc[0] = 10 } func main() { a := [3]int{1,2,3} b := []int{1,2,3} updateArray(a) updateSlice(b) fmt.Println(a) // [1 2 3] fmt.Println(b) // [10 2 3] }
Anahtar özellikler:
Fonksiyon içinde dilimin uzunluğunu değiştirirseniz ne olur? Bu, orijinal dilimi etkiler mi?
Hayır, dilimin uzunluğunu (örneğin, slc = slc[:2] ile) fonksiyon içinde değiştirmek yalnızca yerel başlık kopyasını etkiler. Orijinal dilim değişmeden kalır.
Append operatörü, değiştirilen dilimi aynı bellek alanında mı döner?
Gerekli alan yoksa, yeni bir dizi oluşturularak yeni bir diziye işaretçi geri döner. Eski dizi olduğu gibi kalır.
Kod örneği:
s := []int{1,2,3} s2 := append(s, 4, 5, 6) // s2 yeni bir bellek alanında olabilir
Dilim ile diziye veya tam tersine atanabilir mi?
Hayır. []int ve [5]int farklı türlerdir. Bir diziyi dilim olarak geçirmek için arr[:] dönüşümünü kullanmak gerekir. Tersi mümkün değildir.
Junior geliştirici, diziyi bir fonksiyona geçirerek güncelleme işlevi uyguladı ve değişikliklerin orijinal diziye uygulanacağını bekledi. Düzeltmeler "kaydedilmedi".
Artılar:
Eksiler:
Fonksiyon bir dilim alıyordu ve açıkça değiştirilen bir kopyayı döndürüyordu, bu da etkinin tahmin edilebilirliğini artırıyordu. Tüm değişiklikler bilinçliydi, veriler "sızmadı" ve gizlice değiştirilmedi.
Artılar:
Eksiler: