Ownership: Rust’ın Belirleyici Özelliği
Rust’ta bellek yönetimi, dilin en güçlü yönlerinden biridir. Bu yönetim sistemi, yazılımcıların bellek sızıntıları veya yarış durumları gibi hatalardan kaçınmasını sağlar. Burada devreye giren kavramlardan ilki ownership (sahiplik). Her bir veri parçası, bir sahibi tarafından kontrol edilir ve bir veri parçası yalnızca bir kez sahip olunabilir. Yani, bir değişken bir değeri aldığında, o değerin sahipliği ona ait olur.
Bu sistemde önemli olan şey, bir veri parçası bir kez sahip olunduğunda, başkalarına devredilemez. Eğer başka bir değişken bu veriyi alırsa, ilk değişkenin sahipliği kaybolur ve bu, verinin doğru bir şekilde yönetilmesini sağlar. Ancak bu özellik, bazen karışıklıklara yol açabilir. Şimdi, size sık karşılaşılan bir hatayı gösterelim:
fn main() {
let a = String::from("Hello");
let b = a; // 'a' burada sahipliğini 'b'ye devreder
println!("{}", a); // Hata! 'a' artık geçerli değil.
}
Yukarıdaki kodu çalıştırmaya kalktığınızda, “a” değişkeninin bir daha kullanılmaya çalışıldığını göreceksiniz, fakat bu hatalıdır çünkü ownership "b" değişkenine geçmiştir. Bu durumda, Rust bize "value moved" hatasını verir. Peki, ne yapmalıyız? İşte burada borrow (ödünç alma) kavramı devreye giriyor.
Borrowing: Değişkenlerin Kopyalanması
Bir değişkenin sahibi bir kez devredildikten sonra, başka bir değişkene veri transferi yapmanın başka bir yolu da borrowingdir. Rust'ta veriyi ödünç alırken, iki tür borrowing vardır:
1. Immutable Borrowing (Değiştirilemez ödünç alma)
2. Mutable Borrowing (Değiştirilebilir ödünç alma)
Eğer bir değişkenin değerini ödünç alıyorsanız, iki şey önemli:
- Eğer immutable borrow yapıyorsanız, ödünç aldığınız veri yalnızca okunabilir olur. Yani, bu veri üzerinde herhangi bir değişiklik yapamazsınız.
- Mutable borrow yapıyorsanız, veriyi değiştirmeniz mümkündür, ancak aynı anda yalnızca bir kişiye ödünç verebilirsiniz. Çünkü birden fazla değişkenin aynı anda veriyi değiştirmesi, veri tutarsızlıklarına yol açabilir.
Şimdi örnek kodlarla bakalım:
fn main() {
let mut a = String::from("Hello");
// Immutable borrow
let b = &a; // 'b' 'a' üzerinde sadece okuma yapabilir
println!("{}", b); // Bu geçerli
// Mutable borrow
let c = &mut a; // 'c' veriyi değiştirebilir, ama yalnızca bir tane mutable borrow olmalı
c.push_str(", World!");
println!("{}", c); // Bu da geçerli
println!("{}", a); // Hata! 'a' aynı anda başka bir yerde ödünç alınıyor
}
Yukarıdaki kodda, önce `b` değişkeni ile immutable borrow yapıyoruz, bu geçerli çünkü `b` sadece okuma yapabiliyor. Ancak, sonra `c` değişkenine mutable borrow veriyoruz ve burada dikkat etmemiz gereken nokta, mutable borrow sırasında `a`'ya başka bir ödünç verilmemesi gerektiğidir. Eğer `a`'ya başka bir ödünç verilseydi, burada bir data race riski oluşurdu.
Ownership ve Borrowing Hataları: En Sık Karşılaşılanlar
Rust, bellek hatalarını engellemek için bu kuralları sıkı bir şekilde uygular. Ama bazen bu kurallar kafa karıştırıcı olabilir. İşte en yaygın hata senaryoları:
1. “Value moved” Hatası: Bu hata, bir değeri bir değişkene atadığınızda ve sonra eski değişkeni kullanmaya çalıştığınızda ortaya çıkar. Rust, bir değeri başka bir değişkene atadığında, o değerin sahibini kaybedersiniz. Bu durumu aşmanın yolu, veriyi borrow etmektir.
2. “Cannot borrow immutable twice” Hatası: Aynı anda birden fazla immutable borrow yapmaya çalıştığınızda bu hatayı alırsınız. Rust, verinin birden fazla noktada değişmeden kullanılmasına izin verir, fakat birden fazla değişkenin aynı veriye aynı anda erişmesini engeller.
3. “Cannot borrow as mutable more than once” Hatası: Aynı veriyi aynı anda birden fazla mutable olarak ödünç almaya çalıştığınızda bu hata meydana gelir. Bu, birden fazla borçlunun veriyi aynı anda değiştirebilmesini engellemek için yapılır.
Sonuç: Rust ile Belirgin Bir Bellek Güvenliği Sağlayın
Rust’ın ownership ve borrowing kuralları başlangıçta zorlayıcı gibi görünse de, bu kurallar sayesinde programlarımızda bellek hatalarından kaçınabiliyoruz. Bu özelliklerin anlaşılması, Rust’ı öğrenmenin en önemli aşamalarından biridir. İlk başta kafa karıştırıcı olabilir, ama bir kez alıştığınızda, Rust’ın sunduğu güçlü ve güvenli bellek yönetimi ile çok daha sağlam ve verimli programlar yazabileceksiniz.
Unutmayın, Rust, bellek yönetimi konusunda size yalnızca yardıcı olamaz, aynı zamanda programlarınızı çok daha güvenli hale getirebilir. Bu kuralları öğrenmek zaman alabilir, ancak sonunda sizi daha güçlü bir yazılımcı yapacaktır!