Ownership Nedir? Nasıl Çalışır?
Rust’ın bellek yönetimi farklıdır. C ve C++ gibi dillerde "manuel bellek yönetimi" kullanırken, Rust'ta bellek yönetimi "ownership" adı verilen bir sistemle yapılır. Bir değişkenin sahibi olduğu belleği belirli kurallar altında kullanabilmesi, hatasız bir program yazmanıza olanak tanır.
Her değişkenin bir sahibi vardır ve bu sahiplik, belirli kurallara tabidir. Bu kurallar sayesinde, bellek sızıntıları, kullanım hataları veya veri yarışları (data races) gibi sorunlar önlenir. Ancak "ownership" ile ilgili ilk başta karşılaşacağınız hata, genellikle bir değişkenin aynı anda iki yerden erişilmeye çalışılmasıdır. Bu durum, Rust'ın sahiplik kuralları gereği hataya yol açar.
Ownership Hatası ile Tanışma
Rust'ta en yaygın "ownership" hatalarından biri, bir değişkenin bir fonksiyona geçtikten sonra kullanılamamasıdır. Çünkü Rust, bir değişkenin sahibi sadece bir fonksiyona ait olduğunda, belleğin doğru şekilde yönetilmesini garanti eder. Bu sebeple değişken, fonksiyon içinde bir kez kullanıldıktan sonra, tekrar kullanılamaz.
Mesela bir fonksiyon içinde bir değişkeni "ownership" olarak geçtiğinizde, bu değişken fonksiyon sonrasında geçerli olamaz. Aşağıdaki kod parçası buna güzel bir örnek:
fn sahiplik_ornek() {
let x = String::from("Merhaba Rust");
let y = x; // x'in ownership'i y'ye geçiyor
println!("{}", x); // Hata! x artık geçerli değil
}
Burada, `x` değişkeni, fonksiyona geçtikten sonra "ownership" haklarını `y`'ye devreder. Bu da demek oluyor ki, `x` artık geçerli değil ve onu kullanmaya çalışmak, "ownership" hatasına yol açar.
Borrowing ve Referanslar
Rust'ta "borrowing", yani ödünç verme, "ownership" ve "borrowing" arasında çok ince bir çizgi bulunur. Bir değişkeni ödünç alırken, hem "immutable" (değiştirilemez) hem de "mutable" (değiştirilebilir) referanslar kullanabilirsiniz. Ancak, burada da bazı kurallar vardır. Aynı anda hem mutable hem de immutable referanslara sahip olamazsınız. İşte bu kurallar bazen kafa karıştırıcı olabilir.
Aşağıdaki örneği gözden geçirelim:
fn borrowing_ornek() {
let mut x = String::from("Merhaba Dünya");
let y = &x; // Immutable referans
let z = &x; // Başka bir immutable referans
println!("{}", y); // Geçerli
println!("{}", z); // Geçerli
let w = &mut x; // Hata! Mutable referans izin verilmiyor
}
Burada, `x` değişkeni üzerinde aynı anda iki tane immutable referans (`y` ve `z`) kullanabilirken, bir tane mutable referans (`w`) eklemeye çalıştığınızda, Rust size hata verir. Çünkü bu, veri yarışlarına yol açabilecek bir durumdur.
Borrowing Hataları ve Çözüm Yolları
Rust'ta "borrowing" sırasında karşılaşılan bir diğer yaygın hata, referansın geçerli olduğu sürede ilgili veriye erişmeye çalışmaktır. Yani, bir referans üzerinden veriye erişirken, verinin sahibi olan değişkenin ömrü sona ermişse, o veriye erişim yapmanız mümkün olmayacaktır. Örneğin:
fn invalid_borrow() {
let s = String::from("Merhaba");
let r = &s; // Immutable referans
drop(s); // s'yi düşürüyoruz (geçerli değil)
println!("{}", r); // Hata! r geçersiz
}
Bu durumda, `r`'yi kullanmaya çalıştığınızda, Rust referansın geçersiz olduğunu belirtir çünkü `s`'nin ömrü sonlanmıştır.
Sonuç: Rust ile Güvenli Kod Yazmak
Rust’ın "ownership" ve "borrowing" sistemleri, başlangıçta zorlayıcı olabilir. Ancak bu sistem, bellek güvenliği ve program hatalarını önlemek için oldukça güçlü bir mekanizmadır. Başlangıçta karşılaştığınız her hata, sizi daha güçlü bir programcı yapacaktır. Sabırlı olun ve her hatayı bir öğrenme fırsatı olarak değerlendirin.
Rust’ta her şeyin temelinde güvenlik ve verimlilik yatar. Bu dili öğrendikçe, onun ne kadar güçlü olduğunu ve size sunduğu güvenli ortamı daha iyi anlayacaksınız. Başlangıçta bu hatalarla karşılaşmanız kaçınılmaz, ancak her hata size Rust’ın nasıl çalıştığını öğretmek için bir fırsat sunar.