Sorunun Tarihi
Rust'ta türler genellikle diğer değerleri kapsar (örneğin, Box, Rc) ve geliştiricilerin iç içe geçmiş değerlere, C++'taki işaretçiler gibi saydam bir şekilde erişim istemesi nedeniyle Deref (ve DerefMut) adlı bir trait ve yöntemler ile operatörler aracılığıyla erişim için özel bir otomatik deref mantığı eklendi.
Sorun
İşaretçilerin ve akıllı işaretçilerin ne zaman ve nasıl otomatik olarak genişletileceği konusundaki karmaşa, derleme hatalarına, beklenmeyen yöntem davranışlarına ve bazen de gereksiz kopyalamalar veya ödünç alma nedeniyle alt-optimal koda yol açabilir.
Çözüm
Deref trait'i kendi genişletme kuralınızı tanımlamanıza izin verir (örneğin, Box<T> Deref'i uyguladığı için T gibi davranır). Otomatik deref sistemi, yöntemler ve operatörlere erişim sırasında Deref türlerine olan referansları "genişletmeye" çalışır. Bu, aşağıdakileri yazmanıza olanak tanır:
use std::rc::Rc; fn print_len(s: &str) { println!("{}", s.len()); } let s: Rc<String> = Rc::new("hello".into()); print_len(&s); // otomatik deref: &Rc<String> -> &String -> &str
Anahtar özellikler:
* operatörünün yanı sıra referans türleriyle eşleme sırasında çalışır.Geliştiricinin "beklediği" her zaman auto-deref gerçekleşir mi?
Hayır: deref koersiyonu yalnızca yöntem çağrısı sırasında veya bir Referans Hedefi üzerinden belirtilen başka bir türe referansa ihtiyaç duyulduğunda gerçekleşir. Tüm ifadelerde çalışmaz, örneğin desen eşleştirmede.
Deref koersiyonu, ödünç alma ve sahip olma kurallarını bozabilir mi?
Hayır. Deref koersiyonu tamamen ödünç alma kurallarına riayet eder - Deref aracılığıyla iki mutable referans almak, Rust'ın sahiplik güvenliğini ihlal edemez.
T ve U arasında auto-deref mümkün mü, eğer T: Deref<Target=U> ise ve her iki tür açıkça ilişkili değilse?
Evet, &U bekleyen bir işlev çağrısı yapıldığında, &T ile geçiş yapmak, T'nin Deref<Target=U> uygulaması durumunda otomatik bir dönüşüm ile sonuçlanır.
Kod örneği:
struct Wrapper(String); impl std::ops::Deref for Wrapper { type Target = String; fn deref(&self) -> &Self::Target { &self.0 } } fn takes_str(s: &str) {} let w = Wrapper("mytext".into()); takes_str(&w); // otomatik deref: &Wrapper -> &String -> &str
Bir geliştirici kendi akıllı işaretçisini uyguladı, ancak Deref uygulamasını eklemedi ve türünün normal bir değer gibi davranmasını bekledi.
Artılar:
Tür derlenir ve iç içe geçmiş değere açıkça erişim sağlanabilir.
Eksiler:
Yöntem çağrıları sırasında otomatik deref çalışmayı durdurur, stdlib ve üçüncü taraf kütüphanelerle kullanımda rahatsızlık yaratır.
Kendi sarmalayıcı yapısı, Box gibi Deref ve DerefMut'i uygular, tüm standart fonksiyonlarla pürüzsüz bir entegrasyon sağlar.
Artılar:
Çoğu dil fonksiyonunun saydam çalışması, kullanım kolaylığı, temizlik ve diğer kodla yumuşak entegrasyon.
Eksiler:
Hedef türün belirsiz olduğu durumlarda Deref arayüzünün gereksiz yere karmaşık hale gelme riski.