2017-06-27 5 views
3

Der CodeUnbefriedigend Merkmal gebunden BETEILIGUNG Typ zugeordnet

pub trait Q<S> { 
    fn f(); 
} 

pub trait A { 
    type I; 
    type F: Q<Self::I>; 
} 

// this works (1) 
// 
// pub struct S<T> 
// where 
//  T: A 
// {     

// unsatisfied trait bound (2) 
pub struct S<T>         
where 
    T: A<I = bool>, 
{ 

    t: T, 
} 

zu kompilieren schlägt fehl:

error[E0277]: the trait bound `<T as A>::F: Q<bool>` is not satisfied 
    --> src/main.rs:18:1 
    | 
18 |/pub struct S<T>         
19 | | where 
20 | |  T: A<I = bool>, 
21 | | { 
22 | |  t: T, 
23 | | } 
    | |_^ the trait `Q<bool>` is not implemented for `<T as A>::F` 
    | 
    = help: consider adding a `where <T as A>::F: Q<bool>` bound 
    = note: required by `A` 

Interessanterweise funktioniert es, wenn Sie die auf Kommentar Leitung (1) anstelle von (2) zu verwenden. Es funktioniert auch, wenn Sie den zugehörigen Typ I in einen generischen Typ umwandeln (schreiben Sie trait A<I> und A<bool>).

impl<T> S<T> 
    where T: A 
{ 
    fn g() { 
     T::F::f() 
    } 
} 

gelingt es mit der Linie (1) oder generischem Typ I wird so T::F : Q<bool> in der Tat in den Fällen angenommen.

Warum wird die Eigenschaft automatisch mit Zeile (1) oder generischen Typen angenommen, aber nicht mit Zeile (2)?

Können wir den obigen Code beheben, ohne jedes Mal where T::F: Q<bool> anzuhängen, wenn wir T: A<I=bool> verwenden?

Antwort

4

Ab Rust 1.18 muss der Compiler diese Grenzen schreiben, damit die Typen well-formed sind. Grundsätzlich, um die Grenze T: A<I = bool> zu halten, ist es erforderlich, dass die Grenze T::F: Q<bool> auch gilt. Zum Beispiel versucht, wenn irgendeine Art A wie folgt umzusetzen:

struct Y; 
struct Z; 

impl A for Y { 
    type I = bool; 
    type F = Z; // Z does not implement Q<bool> 
} 

dann würde Y nicht wohlgeformt werden, weil die gebundene T::F: Q<bool> nicht gilt (und in der Tat, gibt der Compiler einen Fehler auf der impl) . Aber frustrierend, für jetzt, muss die Grenze T::F: Q<bool> explizit gegeben werden, wann immer die Grenze T: A<I = bool> erscheint. In gewisser Weise beruhigt es den Compiler, hey, T::I = bool dort auch!

Warum wird die Eigenschaft automatisch mit Zeile (1) oder generischen Typen angenommen, aber nicht mit Zeile (2)?

Mit Leitung (1), würde das gebundene T::F: Q<T::I> sein, die (zum Self substituiert mit T) genau das Erfordernis A ist. Tatsächlich können wir schreiben auch die gebundene äquivalent wie folgt aus:

pub trait A 
where 
    Self::F: Q<Self::I>, 
{ 
    type I; 
    type F; 
} 

Mit Leitung (2), die gebundene T::F: Q<bool> aussehen kann, wie es ist nur eine Frage der T::I mit bool ersetzen, aber dieser Unterschied ist wichtig für den Compiler; T::I ist ein assoziierter Typ, während bool ein konkreter Typ ist.


Die Rust-Entwickler erwägen, den Compiler zu verbessern, so dass Grenzen wie diese müssen alle über den Ort von having the compiler infer those bounds nicht müssen wiederholt werden.

Verwandte Themen