2016-06-06 7 views
1

Versuchen, ein Merkmal Gussteil Problem zu überschreiben, here beschrieben. Steckte die Eigenschaft Funktion bei der Umsetzung, die die Enum-Instanz mit eigener Implementierung liefert innen:Rust Merkmal Objekt & Selbst kann nicht in einer Merkmal Standardfunktion verwendet werden

//the "trait matcher" enum 
enum Side<'a> { 
    Good(&'a GoodDude), 
    Bad(&'a BadDude), 
} 

//very general trait 
trait Dude { 
    fn who_am_i(&self) -> Side; 
    fn do_useful_stuff(&self); 
} 

//specific trait #1 
trait GoodDude: Dude { 
    fn who_am_i_inner(&self) -> Side { 
     Side::Good(&self) 
    } 

    fn save_the_world(&self); 
} 

//specific trait #2 
trait BadDude: Dude { 
    fn who_am_i_inner(&self) -> Side { 
     Side::Bad(&self) 
    } 

    fn do_evil(&self); 
} 

Aber aus irgendeinem Grunde die Zusammenstellung dieses Teils nicht mit E0277:

trait GoodDude: Dude {   
    fn who_am_i_inner(&self) -> Side { 
     Side::Good(&self) //&self should be &GoodDude, but compiler says it is not... 
    } 

    fn save_the_world(&self); 
} 

und Ergebnissen in:

<anon>:16:20: 16:25 error: the trait `GoodDude` is not implemented for the type `&Self` [E0277] 
<anon>:16   Side::Good(&self) 
          ^~~~~ 
<anon>:16:20: 16:25 help: see the detailed explanation for E0277 
<anon>:16:20: 16:25 note: required for the cast to the object type `GoodDude` 

Kann dies ausgearbeitet werden?

Voll Beispiel: https://play.rust-lang.org/?gist=8ae2384e401da76c16214c4a642ce8b4&version=stable&backtrace=0

+1

Versuchen Sie 'Side :: Good (self)' anstelle von 'Side :: Good (& self)'. – kennytm

+0

kann ich nicht. Der Implementierer der Eigenschaften kann eine riesige Struktur sein, ich muss dort Ausleihen und Merkmalsobjekte verwenden. Außerdem wird sofort nach der Größe gefragt (das Merkmal 'core :: marker :: Sized' ist nicht implementiert) – snuk182

+0

' fn name (& self) 'kann als' fn name (self: & Self) 'entzuckert werden. Typ der 'self' Variablen ist' & Self'. – aSpex

Antwort

4

Zum einen ist die Art von self in fn who_am_i_inner bereits eine Referenz, so dass Sie & nicht brauchen.

fn who_am_i_inner(&self) -> Side { 
    Side::Good(self) 
} 

Aber dann klagt rustc ...

<anon>:13:20: 13:24 error: the trait `core::marker::Sized` is not implemented for the type `Self` [E0277] 
<anon>:13   Side::Good(self) 
          ^~~~ 
<anon>:13:20: 13:24 help: see the detailed explanation for E0277 
<anon>:13:20: 13:24 note: `Self` does not have a constant size known at compile-time 
<anon>:13:20: 13:24 note: required for the cast to the object type `GoodDude` 

Zwar ist die Fehlermeldung ist sehr unübersichtlich und E0277 ist um etwas ganz anderes. Lassen Sie uns den nächtlichen Compiler versuchen stattdessen, die Nachrichten besser Fehler gibt:

error: the trait bound `Self: std::marker::Sized` is not satisfied [--explain E0277] 
    --> <anon>:13:20 
13 |>   Side::Good(self) 
    |>     ^^^^ 
help: consider adding a `where Self: std::marker::Sized` bound 
note: required for the cast to the object type `GoodDude` 

OK lassen Sie uns versuchen, die where Self: Sized hinzuzufügen:

fn who_am_i_inner(&self) -> Side where Self: Sized { 
    Side::Good(self) 
} 

und jetzt funktioniert es.

Welt gespeichert. Drücken Sie eine beliebige Taste, um fortzufahren
die 4. mit Ihnen
Pew Pew Pew
Luke ich bin yr Vater


Die where Self: Sized ist Rust Art und Weise, dass the method cannot be used from trait objects bedeuten werden. Wir sagen, dass die Methode von "object-safety" ignoriert wird, oder "kann nicht virtuell sein", wenn Sie C++ mögen.

Der Effekt ist, dass, wenn alles, was Sie haben, ist luke: &GoodDude, dann können Sie nicht anrufen luke.who_am_i_inner() seit *luke hat eine unbekannte Größe.

Der Grund, warum wir die Methode nicht objektsicher machen müssen, liegt an der Besetzung &Self → &GoodDude. In Rust ist ein Merkmalsobjektreferenz wie &GoodDude ein Fettzeiger, intern wird es als ein 2-Tupel (pointer, method_table) dargestellt. In einem Merkmal ist der self jedoch ein Thin-Pointer.

Wir können einen Thin-Pointer nicht in einen Fat-Pointer konvertieren, da eine fehlende Information, die method_table, existiert. Dies kann ausgefüllt werden, wenn wir den konkreten Typ kennen. Deshalb fügen wir die where Self: Sized hinzu.

Wenn Sie who_am_i_inner objektsicher machen möchten, können Sie keine Standardimplementierung bereitstellen.

+0

Danke. Dies beschreibt explizit, was ich brauche. Jetzt kann ich diesen Ansatz zumindest als eine Art "Traitcasting" verwenden. – snuk182

+0

Siehe [diese Idee] (https://users.rust-lang.org/t/how-can-i-cast-self-to-a-trait-object-in-default-method/7993/8?u = adrianheine). –

Verwandte Themen