Rust Borrow Checker Hataları: 7 Yaygın Hata ve Çözümleri (2026)

01.01.2026 03:29 Haber

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.

Borrow Checker Nedir? (What is Borrow Checker?)

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!

? Neden Önemli? / Why Important?

Borrow checker sayesinde Rust, garbage collector olmadan memory-safe kod yazmanızı sağlar. Bu da C++ performansı + bellek güvenliği demek!

Ownership ve Borrowing Temelleri:

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
}

Temel Kurallar (Core Borrowing Rules)

Rust'ın borrow checker'ı iki temel kurala dayanır. Alesta Web olarak bunları şöyle özetliyoruz:

⚠️ Altın Kurallar / Golden Rules:
  1. Aynı anda sadece BİR mutable reference VEYA birden fazla immutable reference olabilir
  2. Reference, referans verdiği değerden daha uzun yaşayamaz (lifetime)

Kural 1: Mutable vs Immutable Reference:

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);
}

Kural 2: Lifetime (Yaşam Süresi):

// ❌ 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
}

7 Yaygın Borrow Checker Hatası ve Çözümleri

Alesta Web olarak Rust projelerinde en çok karşılaştığımız hataları ve çözümlerini paylaşıyoruz:

Hata 1: "Cannot borrow as mutable because it is also borrowed as immutable"

❌ Hatalı Kod / Buggy Code:

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

✅ Çözüm / Fix:

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
}

Hata 2: "Value moved here" / "Use of moved value"

❌ Hatalı Kod:

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`

✅ Çözüm:

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
}

Hata 3: "Cannot move out of borrowed content"

❌ Hatalı Kod:

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
}

✅ Çözüm:

// 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
}

Hata 4: Loop İçinde Mutable Borrow

❌ Hatalı Kod:

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
        }
    }
}

✅ Çözüm:

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
}

Hata 5: Struct Field'larını Ayrı Ayrı Borrow Etme

❌ Hatalı Kod:

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);
    }
}

✅ Çözüm (Destructuring):

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!
    }
}

Hata 6: Self Referential Struct

Problem ve Çözüm:

// ❌ 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]
    }
}

Hata 7: Closure ile Borrow

❌ Hatalı Kod:

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();
}

✅ Çözüm:

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
}

Pratik İpuçları (Practical Tips)

Alesta Web olarak Rust'ta borrow checker ile barışık yaşamak için şu ipuçlarını öneriyoruz:

✅ En İyi Uygulamalar / Best Practices:
  • Küçük scope'lar kullan - borrow'lar erken bitsin
  • Clone'dan korkma - performans kritik değilse kullan
  • Rc ve RefCell öğren - shared ownership için
  • Clippy kullan: cargo clippy
  • Rust Playground'da dene: play.rust-lang.org

Rc ve RefCell Örneği:

use 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]
}

İleri Teknikler (Advanced Techniques)

Lifetime Annotation

Lifetime Örneği:

// '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
}

? Kaynaklar ve Referanslar / Sources and References

Alesta Web olarak tüm örnekleri test ettik ve doğruladık.

✅ Borrow Checker Artık Dost! (Borrow Checker is Now Your Friend!)

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:

  • ✅ Ownership ve borrowing anlaşıldı (Ownership understood)
  • ✅ 7 yaygın hata çözüldü (7 common errors fixed)
  • ✅ Best practices öğrenildi (Best practices learned)
  • ✅ Lifetime annotations kavrandı (Lifetimes understood)

Faydalı Linkler / Useful Links:

© 2026 AlestaWeb - Tüm hakları saklıdır.

WM Tools
💫

WebMaster Tools

15 Profesyonel Araç