Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Drop Trait’i ile Temizlik Sırasında Kod Çalıştırmak

Akıllı işaretçi deseni için önemli ikinci trait Droptur. Bir değer kapsam dışına çıkmak üzereyken ne olacağını özelleştirmenizi sağlar. Drop uygulamasını herhangi bir tür için yazabilir ve böylece dosya, ağ bağlantısı gibi kaynakları bırakmak için çalışacak kodu belirleyebilirsiniz.

Dropu akıllı işaretçiler bağlamında ele alıyoruz; çünkü Drop çoğunlukla akıllı işaretçi yazarken kullanılır. Örneğin Box<T> bırakıldığında, kutunun işaret ettiği öbek alanı serbest bırakılır.

Bazı dillerde, bazı türlerin örnekleriyle işiniz bittiğinde belleği ya da kaynağı serbest bırakacak kodu programcının elle çağırması gerekir. Dosya tanıtıcıları, soketler ve kilitler buna örnektir. Programcı unutursa sistem zorlanabilir hatta çökebilir. Rust’ta ise bir değer kapsam dışına çıktığında hangi kodun çalışacağını belirtirsiniz; derleyici bu kodu uygun yerlere otomatik ekler.

Bir değer kapsam dışına çıktığında çalışacak kodu Drop trait’ini uygulayarak belirlersiniz. Bu trait, selfi değiştirilebilir referans olarak alan drop adlı bir yöntem ister. Rust’ın dropu ne zaman çağırdığını görmek için şimdilik bu yönteme println! ekleyelim.

Liste 15-14, kapsam dışına çıkınca mesaj basan OzelAkilliIsaretci yapısını gösterir.

Filename: src/main.rs
struct OzelAkilliIsaretci {
    veri: String,
}

impl Drop for OzelAkilliIsaretci {
    fn drop(&mut self) {
        println!(
            "`{}` verisine sahip OzelAkilliIsaretci bırakılıyor!",
            self.veri
        );
    }
}

fn main() {
    let c = OzelAkilliIsaretci {
        veri: String::from("benim şeylerim"),
    };
    let d = OzelAkilliIsaretci {
        veri: String::from("diğer şeyler"),
    };
    println!("OzelAkilliIsaretciler oluşturuldu");
}
Listing 15-14: Temizlik kodunun yer alacagi Drop uygulamali OzelAkilliIsaretci yapisi

Drop trait’i prelude içinde olduğu için ayrıca kapsamaya almamız gerekmez. OzelAkilliIsaretci için Drop uyguluyor ve drop içinde bir mesaj yazdırıyoruz. Gerçek hayatta bu gövdeye kaynak temizleme mantığı konurdu.

main içinde iki OzelAkilliIsaretci oluşturup ardından OzelAkilliIsaretciler oluşturuldu yazdırıyoruz. main sonunda bu değerler kapsam dışına çıkar ve Rust dropu otomatik çağırır. Yani dropu bizim elle çağırmamıza gerek yoktur.

Programı çalıştırınca şunu görürüz:

$ cargo run
   Compiling birak-ornegi v0.1.0 (file:///projects/birak-ornegi)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.60s
     Running `target/debug/birak-ornegi`
OzelAkilliIsaretciler oluşturuldu
`diğer şeyler` verisine sahip OzelAkilliIsaretci bırakılıyor!
`benim şeylerim` verisine sahip OzelAkilliIsaretci bırakılıyor!

Rust değerler kapsam dışına çıktığında dropu otomatik çağırır. Değişkenler oluşturulma sırasının tersine bırakılır; bu yüzden d, cden önce bırakılır.

Bazen bir değeri kapsam sonunu beklemeden daha erken temizlemek isteyebilirsiniz. Örneğin kilit yöneten akıllı işaretçilerde, kilidi erkenden bırakıp aynı kapsam içindeki başka kodun kilidi almasına izin vermek isteyebilirsiniz. Rust, Drop trait’inin drop yöntemini elle çağırmanıza izin vermez; bunun yerine standart kütüphanedeki std::mem::drop fonksiyonunu kullanırsınız.

Liste 15-14’teki maini değiştirip drop yöntemini elle çağırmak istersek, Liste 15-15’teki kod çalışmaz.

Filename: src/main.rs
struct OzelAkilliIsaretci {
    veri: String,
}

impl Drop for OzelAkilliIsaretci {
    fn drop(&mut self) {
        println!(
            "`{}` verisine sahip OzelAkilliIsaretci bırakılıyor!",
            self.veri
        );
    }
}

fn main() {
    let c = OzelAkilliIsaretci {
        veri: String::from("bir miktar veri"),
    };
    println!("OzelAkilliIsaretci oluşturuldu");
    c.drop();
    println!("OzelAkilliIsaretci, main bitmeden önce bırakıldı");
}
Listing 15-15: Temizligi erken yapmak icin Drop trait’indeki dropu elle cagirmaya calismak

Derlersek şu hatayı alırız:

$ cargo run
   Compiling birak-ornegi v0.1.0 (file:///projects/birak-ornegi)
error[E0040]: explicit use of destructor method
  --> src/main.rs:16:7
   |
16 |     c.drop();
   |       ^^^^ explicit destructor calls not allowed
   |
help: consider using `drop` function
   |
16 -     c.drop();
16 +     drop(c);
   |

For more information about this error, try `rustc --explain E0040`.
error: could not compile `birak-ornegi` (bin "birak-ornegi") due to 1 previous error

Hata açıkça drop çağrısının yasak olduğunu söyler. Buradaki destructor, örneği temizleyen fonksiyon için kullanılan genel terimdir. Yapıcı (constructor) nasıl örnek oluşturuyorsa, destructor da örneği temizler.

Rust buna izin vermez; çünkü kapsam sonunda yine otomatik drop çağrılırdı. Böylece aynı değer iki kez temizlenmeye çalışılırdı.

Bu yüzden bir değeri erkenden bırakmak istiyorsak, std::mem::drop fonksiyonunu çağırırız. Değeri fonksiyona argüman olarak veririz; prelude içinde olduğu için ayrıca use yazmamız gerekmez. Liste 15-16 bunu gösterir.

Filename: src/main.rs
struct OzelAkilliIsaretci {
    veri: String,
}

impl Drop for OzelAkilliIsaretci {
    fn drop(&mut self) {
        println!(
            "`{}` verisine sahip OzelAkilliIsaretci bırakılıyor!",
            self.veri
        );
    }
}

fn main() {
    let c = OzelAkilliIsaretci {
        veri: String::from("bir miktar veri"),
    };
    println!("OzelAkilliIsaretci oluşturuldu");
    drop(c);
    println!("OzelAkilliIsaretci, main bitmeden önce bırakıldı");
}
Listing 15-16: Bir degeri kapsam disina cikmadan once acikca birakmak icin std::mem::drop cagirmak

Bu kodun çıktısı şöyledir:

$ cargo run
   Compiling birak-ornegi v0.1.0 (file:///projects/birak-ornegi)
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.73s
     Running `target/debug/birak-ornegi`
OzelAkilliIsaretci oluşturuldu
`bir miktar veri` verisine sahip OzelAkilliIsaretci bırakılıyor!
OzelAkilliIsaretci, main bitmeden önce bırakıldı

OzelAkilliIsaretci oluşturuldu ile main bitmeden önce bırakıldı satırları arasında, bırakma mesajının yazdırılması c değerinin o noktada temizlendiğini gösterir.

Drop uygulamasıyla verdiğiniz kodu birçok yaratıcı şekilde kullanabilirsiniz; örneğin kendi bellek ayırıcınızı yazabilirsiniz. Drop ve Rust’ın sahiplik sistemi sayesinde temizlik kodunu hatırlamak zorunda kalmazsınız; Rust bunu sizin için yapar.

Ayrıca hâlâ kullanılan bir değeri yanlışlıkla temizlemekten de korkmanız gerekmez. Referansların geçerliliğini koruyan sahiplik sistemi, dropun yalnızca değer artık kullanılmıyorken bir kez çağrılmasını da sağlar.