2016-06-29 24 views
5

Örnek 1'in neden kodladığı ancak örnek 2'nin neden derleme hatası verdiğini açıklayabilir misiniz? Açıklama çok uzun ve karmaşıksa (tutarlılık kurallarının açıklanacağından şüphelendiğim gibi), o zaman gibi basit bir cevaptan memnun olurum. "Güven bana, dilin örnek 2 kodunu reddetmesinin iyi bir nedeni var".Uyum kuralları neden "bazı yerel türler için type parametresi olarak type parametresi kullanılmalıdır" hatasını yükseltir?

Örnek 1:

use std::ops::Index; 

struct Bounded { 
    idx: usize 
} 

impl Index<Bounded> for [i32; 4] { 
    type Output = i32; 

    fn index(&self, b: Bounded) -> &i32 { 
     unsafe { self.get_unchecked(b.idx) } 
    } 
} 

Örnek 2:

use std::ops::Index; 

struct Bounded { 
    idx: usize 
} 

impl<T> Index<Bounded> for [T; 4] { 
    type Output = T; 

    fn index(&self, b: Bounded) -> &T { 
     unsafe { self.get_unchecked(b.idx) } 
    } 
} 

// error: type parameter `T` must be used as the type parameter for 
// some local type (e.g. `MyStruct<T>`); only traits defined in the 
// current crate can be implemented for a type parameter [--explain E0210] 
+6

Burada sorun aslında yetim kural değil, tutarlılık kuralı :). Açıklamayı "rustc --explain E0210" ile kontrol edebilirsiniz. – kennytm

+1

@kennytm: Bu bir cevap olmalı mı (biraz ayrıntı ile)? –

cevap

3

O "Orada iyi bir neden", ama iyi bir neden o kadar karışık değil aşağı kaynatın gelmez.

İşte sorun. Bir kütüphane sandığım olduğunu düşünün:

// library.rs 
pub struct Dog; 
pub trait Speak { 
    fn speak(&self); 
} 

Ve bu kütüphane sandığını kullanan iki kasa.

// bark.rs 
extern crate library; 
impl library::Speak for library::Dog { 
    fn speak(&self) { 
     println!("woof"); 
    } 
} 
// woof.rs 
extern crate library; 
impl library::Speak for library::Dog { 
    fn speak(&self) { 
     println!("bark"); 
    } 
} 

Şimdi, bazı nedenlerden dolayı, ben bu kütüphanelerin her ikisini de kullanmak istiyorum:

// main.rs 
extern crate library; 
extern crate woof; 
extern crate bark; 

fn main() { 
    let rex = library::Dog; 
    rex.speak(); 
} 

Ne bu program çıktısı gerekir? library::Dog için library::Speak iki eşit geçerli, ayırt edilemez uygulamaları vardır; doğru bir cevap yok. Daha da kötüsü, orijinal olarak woof'a bağımlı olsaydım ve daha sonra bark eklediyse, kodum derlemeyi durdurdu, veya - daha kötüsü - yanlış şeyi şeffaf bir şekilde yapmaya başlıyordu. Çakışan özellik impls bir Bad Thing ™ 'dir.

Jenerik eklediğinizde kötüleşir. Eğer varsa:

// barkgeneric.rs 
extern crate library; 
impl<T> library::Speak for T { 
    fn speak(&self) { 
     println!("woof"); 
    } 
} 
// woofgeneric.rs 
extern crate library; 
impl<T> library::Speak for T { 
    fn speak(&self) { 
     println!("bark"); 
    } 
} 

Artık çelişkili özellik impls bir sonsuz numarası var. Whoops.

Bu sorunu önlemek için, yetim kurallarımız var. Yetim kurallarının düşüncesi, herhangi bir impl Trait for Type'un bir ve sadece bir tane yerleştirilebildiğinden emin olmaktır. Bu şekilde, impl çatışmaları hakkında endişelenmek zorunda değiliz; Yetim kuralları doğru şekilde kurulursa, doğrudan imkansız olmalılar.

Kurallar şununla eşleşir: impl türünde bir özellik olduğunda, özellik ya da türün geçerli sandıktan gelmesi gerekir. Bu, tüm çakışan örneklerimi işe yaramaz. woof.rslibrary::Dog için library::speak'u uygulayamaz, çünkü bunların hiçbiri sandığından gelmez.

Aynı şekilde, [T; 4] çünkü sandık gelmiyor ve rustcIndex<Bounded> ya da sandık gelen sayılmaz karar verdi, değil impl<T> Index<Bounded> for [T; 4]; can.

Ancak, bu durumda Index<Bounded> ürününüz sizden geldiği için impl Index<Bounded> for [i32; 4] numaranızı iletir.Bu bir hata, ama aynı zamanda sadece amaçlanmış davranışı da mümkündür; Yetim kuralları burada belirttiğimden biraz daha karmaşıktır ve garip şekillerde etkileşimde olabilirler.

Daha ayrıntılı bilgi için bkz. rustc --explain E0117, rustc --explain E0210.