Bir gün, Rust dilini öğrenmeye karar verdiğinizde, kodunuzu derlerken bir hata aldınız. Hatayı incelediğinizde "ownership" ve "borrowing" hakkında bir şeyler yazıldığını gördünüz. “Bu ne demek?” diye düşündünüz. İşte bu yazı tam da o anları anlamlandırmanız için burada.
Ownership Nedir?
Rust'ta, bir veri yalnızca bir yerde sahiplik (ownership) edilir. Yani, bir değişken bir veri parçasına sahip olduğunda, bu verinin yalnızca o değişken tarafından erişilebileceğini belirtiriz. Eğer bu değişken yok olursa, sahip olduğu bellek de otomatik olarak serbest bırakılır.
Bu özellik, Rust'ın bellek güvenliğini sağlama mekanizmasının temelidir. Fakat sahiplik, bazı hataları doğurabiliyor.
Borrowing Nedir?
Ownership'a ek olarak, Rust aynı zamanda *borrowing* kavramını da kullanır. Bir veriyi ödünç almak, o verinin sahipliğine sahip olmadan ona erişim sağlamak anlamına gelir. Rust, verileri ödünç alırken, bu ödünç işlemini “immutable” (değiştirilemez) veya “mutable” (değiştirilebilir) olarak iki farklı şekilde yapmanıza izin verir.
- Immutable Borrowing: Bir veri değiştirilemez şekilde ödünç alındığında, o veri üzerinden yalnızca okuma yapılabilir.
- Mutable Borrowing: Eğer veri üzerinde değişiklik yapmayı planlıyorsanız, değişkenin yalnızca bir kez ödünç alınmasına izin verilir.
Peki, bu iki kavram arasındaki dengeyi kurarken hangi hatalarla karşılaşabilirsiniz? Şimdi, bunun üzerine yoğunlaşalım.
Ownership ve Borrowing Hatalarına Genel Bakış
Rust’ta en yaygın karşılaşılan hatalardan bazıları, sahiplik ve ödünç alma kurallarını ihlal eden hatalardır. Hadi bunları daha yakından inceleyelim.
1. Ownership Hatası: "Use of Moved Value"
Diyelim ki bir değişkene sahip olduğunuz bir veri parçası var. Bu veriyi bir başka değişkene atadığınızda, orijinal değişkenin veriye olan sahipliği kaybolur. Bu durumu kontrol etmediğinizde, Rust derleyicisi “moved value” hatasını verebilir.
Örnek bir kod parçası:
fn main() {
let s1 = String::from("Hello, Rust!");
let s2 = s1; // s1 artık 'moved' oldu
println!("{}", s1); // Hata: s1 artık geçerli değil!
}
Burada, `s1` değişkeni `s2`'ye atandığında, `s1`'in sahipliği `s2`'ye geçer. `s1`’i tekrar kullanmak istediğimizde, Rust derleyicisi hata verir çünkü artık `s1` geçerli değildir. Bu hatayı, sahiplik devrini anlamakla çözebilirsiniz.
2. Borrowing Hatası: "Mutable and Immutable Borrowing at the Same Time"
Bir veri üzerinde hem mutable hem de immutable borrows (ödünç alma) yapmanız da bir hata oluşturur. Rust bu durumu kesinlikle engeller, çünkü aynı anda bir veriye hem değişiklik yapmak hem de ona okuma yapmak bellek hatalarına yol açabilir.
Aşağıdaki kodu göz önünde bulunduralım:
fn main() {
let mut x = 5;
let y = &x; // Immutable borrow
let z = &mut x; // Mutable borrow
println!("y: {}, z: {}", y, z); // Hata: Mutable ve immutable borrow aynı anda yapılmaz!
}
Burada `x` üzerinde hem immutable (y) hem de mutable (z) bir borç yapılmaya çalışılıyor. Rust, bunun tehlikeli olduğunu düşündüğü için derleme aşamasında hata verir. Bunu, yalnızca bir tür borç işlemi yapılacak şekilde düzeltebilirsiniz.
3. Double Borrowing Hatası
Bir değişkeni birden fazla kez ödünç almak da bir hatadır. Bu durum, özellikle veriyi paralel olarak kullanan kodlar için bellek güvenliği açıklarına yol açabilir.
Örnek bir kod:
fn main() {
let s = String::from("Hello");
let t = &s;
let u = &s; // İkinci borç
println!("t: {}, u: {}", t, u); // Hata: Aynı veri birden fazla kez borç alınamaz
}
Burada `s` değişkeninin aynı anda iki farklı değişken (`t` ve `u`) tarafından ödünç alınması bir hata yaratır. Rust, bu tür durumları engeller ve sadece bir borç işlemi yapılmasına izin verir.
Rust’ta Bu Hataları Nasıl Çözebilirsiniz?
Rust’ın sahiplik ve ödünç alma kuralları, başlangıçta zorlayıcı olsa da doğru kullanıldığında güçlü bir bellek güvenliği sağlar. İşte hatalarınızı çözmenize yardımcı olacak bazı ipuçları:
- Sahiplik Değişimi: Eğer bir veri üzerinde işlem yapmayı planlıyorsanız, sahiplik devrini göz önünde bulundurun. Veriyi başka bir değişkene atadığınızda, orijinal değişkeni kullanamayacağınızı unutmayın.
- Borrowing: Bir veri üzerinde hem immutable hem de mutable borç alma işlemleri yapmamaya dikkat edin. Bir veri yalnızca bir kez mutable olarak ödünç alınabilir.
- Lifetime: Rust, lifetime (ömrü) kavramını kullanarak hangi borçların ne zaman geçerli olduğunu kontrol eder. Bu konuda dikkatli olmalısınız.
Rust’ın kuralları, başlarda zorlayıcı olabilir ancak uygulama geliştikçe daha anlaşılır hale gelir. Bu hatalarla karşılaştığınızda panik yapmayın, Rust derleyicisi size her zaman neyin yanlış olduğunu gösterecektir.