Ulaşım
- Adres:Batıkent Mh. 8910 Sk. 6. Etap 1H No: 18 Yeni Toki Eyyübiye / Şanlıurfa (Yeni Alım Satım Karşısı)
- Telefon:0 (545) 528 88 93
- eMail: info@alestaweb.com
Rust öğrenirken en çok karşılaşılan engel nedir biliyor musunuz? Borrow Checker! "Cannot borrow as mutable" veya "value borrowed here after move" hataları sizi çıldırtıyor mu? Alesta Web olarak bu rehberde Rust'ın borrow checker'ını anlamak ve hatalarını çözmek (how to fix) için gereken her şeyi anlatacağız.
Rust'ın borrow checker'ı, memory safety (bellek güvenliği) sağlayan ve C/C++'daki use-after-free, data races gibi hataları derleme zamanında önleyen bir sistemdir. Alesta Web olarak Rust'ı seviyoruz çünkü bu sistem runtime hataları yerine compile-time hatalarla sizi uyarır.
Şöyle düşünün: Bir kitabı (değişkeni) arkadaşınıza ödünç verdiniz (borrow). Kitap onda iken siz o kitabın sayfalarını değiştiremezsiniz, değil mi? İşte Rust'ın mantığı tam olarak bu!
Borrow checker sayesinde Rust, garbage collector olmadan memory-safe kod yazmanızı sağlar. Bu da C++ performansı + bellek güvenliği demek!
fn main() {
let s1 = String::from("hello"); // s1 değerin sahibi (owner)
let s2 = s1; // Ownership s2'ye taşındı (moved)
// println!("{}", s1); // ❌ HATA! s1 artık geçersiz
let s3 = String::from("world");
let s4 = &s3; // Borrowing - s3'ü ödünç al (immutable reference)
println!("{} {}", s3, s4); // ✅ İkisi de kullanılabilir
}
Rust'ın borrow checker'ı iki temel kurala dayanır. Alesta Web olarak bunları şöyle özetliyoruz:
fn main() {
let mut data = vec![1, 2, 3];
// ✅ Birden fazla immutable reference OK
let r1 = &data;
let r2 = &data;
println!("{:?} {:?}", r1, r2);
// ✅ Tek mutable reference OK
let r3 = &mut data;
r3.push(4);
// ❌ HATA! Aynı anda immutable ve mutable reference
// let r4 = &data;
// let r5 = &mut data;
// println!("{:?} {:?}", r4, r5);
}
// ❌ Bu fonksiyon derlenmez
fn dangling_reference() -> &String {
let s = String::from("hello");
&s // ❌ s fonksiyon bitince yok olur, reference geçersiz kalır!
}
// ✅ Doğru yaklaşım: Ownership'i taşı
fn valid_return() -> String {
let s = String::from("hello");
s // Ownership çağırana aktarılır
}
Alesta Web olarak Rust projelerinde en çok karşılaştığımız hataları ve çözümlerini paylaşıyoruz:
fn main() {
let mut vec = vec![1, 2, 3];
let first = &vec[0]; // immutable borrow
vec.push(4); // ❌ mutable borrow - HATA!
println!("{}", first);
}
// Error: cannot borrow `vec` as mutable because it is also borrowed as immutable
fn main() {
let mut vec = vec![1, 2, 3];
// Yöntem 1: İmmutable borrow'u önce bitir
let first = vec[0]; // Copy, borrow değil
vec.push(4);
println!("{}", first);
// Yöntem 2: Scope ile ayır
{
let first = &vec[0];
println!("{}", first);
} // first burada drop olur
vec.push(5); // ✅ Artık OK
}
fn main() {
let s1 = String::from("hello");
let s2 = s1; // s1 moved to s2
println!("{}", s1); // ❌ HATA! s1 moved
}
// Error: borrow of moved value: `s1`
fn main() {
let s1 = String::from("hello");
// Yöntem 1: Clone kullan
let s2 = s1.clone();
println!("{} {}", s1, s2); // ✅ İkisi de geçerli
// Yöntem 2: Reference kullan
let s3 = String::from("world");
let s4 = &s3; // Borrow, move değil
println!("{} {}", s3, s4); // ✅ OK
}
fn take_ownership(s: String) {
println!("{}", s);
}
fn main() {
let vec = vec![String::from("hello")];
let s = &vec[0];
take_ownership(*s); // ❌ Cannot move out of borrowed content
}
// Yöntem 1: Clone kullan
fn main() {
let vec = vec![String::from("hello")];
let s = &vec[0];
take_ownership(s.clone()); // ✅ Clone ile kopyala
}
// Yöntem 2: Fonksiyonu reference alacak şekilde değiştir
fn take_ref(s: &String) {
println!("{}", s);
}
fn main() {
let vec = vec![String::from("hello")];
take_ref(&vec[0]); // ✅ Reference ver
}
fn main() {
let mut vec = vec![1, 2, 3];
for item in &vec {
if *item == 2 {
vec.push(4); // ❌ Cannot borrow as mutable while iterating
}
}
}
fn main() {
let mut vec = vec![1, 2, 3];
// Yöntem 1: İndex ile iterate et
let len = vec.len();
for i in 0..len {
if vec[i] == 2 {
vec.push(4); // ✅ Dikkat: sonsuz döngüye girme!
break;
}
}
// Yöntem 2: Collect ile yeni değerler topla
let mut vec2 = vec![1, 2, 3];
let to_add: Vec<_> = vec2.iter()
.filter(|&&x| x == 2)
.map(|_| 4)
.collect();
vec2.extend(to_add); // ✅ Sonra ekle
}
struct Game {
player: Player,
enemies: Vec,
}
fn update(game: &mut Game) {
let player = &game.player; // immutable borrow
for enemy in &mut game.enemies { // ❌ mutable borrow - HATA!
enemy.attack(player);
}
}
fn update(game: &mut Game) {
let Game { player, enemies } = game; // Ayrı ayrı borrow
for enemy in enemies.iter_mut() {
enemy.attack(player); // ✅ Artık OK!
}
}
// ❌ Bu Rust'ta doğrudan mümkün değil
struct SelfRef {
data: String,
ptr: &String, // ❌ Kendine reference
}
// ✅ Çözüm: Pin ve unsafe veya farklı tasarım
// En kolay çözüm: indeks kullan
struct BetterDesign {
data: Vec,
current_index: usize,
}
impl BetterDesign {
fn current(&self) -> &String {
&self.data[self.current_index]
}
}
fn main() {
let mut data = vec![1, 2, 3];
let closure = || data.push(4); // Closure data'yı mutable borrow eder
println!("{:?}", data); // ❌ data zaten borrowed
closure();
}
fn main() {
let mut data = vec![1, 2, 3];
// Yöntem 1: Closure'ı hemen çağır
{
let mut closure = || data.push(4);
closure();
} // Borrow burada biter
println!("{:?}", data); // ✅ OK
// Yöntem 2: move ile ownership al
let data2 = vec![1, 2, 3];
let closure2 = move || {
println!("{:?}", data2);
};
closure2();
// println!("{:?}", data2); // ❌ data2 moved
}
Alesta Web olarak Rust'ta borrow checker ile barışık yaşamak için şu ipuçlarını öneriyoruz:
cargo clippyuse std::rc::Rc;
use std::cell::RefCell;
fn main() {
// Rc: Shared ownership (reference counting)
let data = Rc::new(RefCell::new(vec![1, 2, 3]));
let data_clone = Rc::clone(&data);
// RefCell: Runtime borrow checking
data.borrow_mut().push(4);
println!("{:?}", data_clone.borrow()); // [1, 2, 3, 4]
}
// 'a lifetime parametresi: dönüş değeri en az x ve y kadar yaşar
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
fn main() {
let s1 = String::from("short");
let result;
{
let s2 = String::from("longer string");
result = longest(&s1, &s2);
println!("{}", result); // ✅ s2 hala scope'ta
}
// println!("{}", result); // ❌ s2 drop edildi
}
Alesta Web olarak tüm örnekleri test ettik ve doğruladık.
Rust borrow checker (ödünç alma denetleyicisi) artık sizin için bir düşman değil, memory-safe kod yazmanızı sağlayan güçlü bir müttefik! Alesta Web olarak bu rehberle Rust yolculuğunuzda size yardımcı olabildiysek ne mutlu bize.
Hızlı Özet / Quick Summary:
Faydalı Linkler / Useful Links:
© 2026 AlestaWeb - Tüm hakları saklıdır.