2016-04-21 7 views
6

Hier ist das Szenario: Ich habe eine Struktur und Eigenschaft Paar haben, wie folgt:Rust Einschränkungen für Generic Type Referenz

trait Operation { 
    fn operation(self) -> u32 
} 

struct Container<T: Sized + Operation> { 
    x:T 
} 

impl <T: Sized + Operation> for Container<T> { 
    fn do_thing(&self) -> u32 { 
     // Do something with the field x. 
    } 
} 

Die Operation erfordert einen Pass-by-Wert Anruf, wenn verwendet, und die Ausgabe kommt mit etwas ähnliches zu "do_thing". Ich würde es vorziehen, keine Kopiersemantik für den Typ T zu erzwingen und möchte eine Abhilfe dafür. Im Wesentlichen würde ich gerne Folgendes wissen:

  1. Ist es möglich, Merkmalsbeschränkungen für Referenzen von Typ Parameter zu erzwingen? Etwas in der Art von: struct Container<T: Sized + Operation> where &T: Operation { ... }. Ich habe versucht, mit der Syntax etwas zu misten, und ich hatte keinen Erfolg.
  2. Wenn das oben nicht möglich ist, ist es theoretisch möglich; d.h. es verletzt keine Kohärenzeigenschaften oder etwas in dieser Richtung?
  3. Wäre es möglich, ein zweites Merkmal zu schaffen, sagt Middle: Operation, wo Middle, dass alle Implementierer von Middle erfordern kann, T, auch Operation für &T zur Umsetzung erforderlich sind.
  4. Wenn keine der oben genannten Möglichkeiten möglich ist, gibt es dafür eine andere häufige Problemumgehung?

Einige Anmerkungen:

  • ich keinen Zugriff haben die Operation Eigenschaft zu ändern, ist es gegeben, und es ist das, was ich bin mit zu arbeiten.
  • Es gibt eine old RFC, die über einige Änderungen an Where-Klauseln spricht, aber ich habe nichts in Bezug auf Referenzbedingungen gefunden.
  • Compiler-Version: rustc 1.8.0 (db2939409 2016-04-11)

Antwort

9

Ja, können Sie &T beschränken Sized + Operation zu sein. Sie müssen Higher-Rank Trait Bounds und where verwenden.

trait Operation { 
    fn operation(self) -> u32; 
} 

struct Container<T> 
    where for<'a> &'a T: Sized + Operation 
{ 
    x: T, 
} 

impl<T> Container<T> 
    where for<'a> &'a T: Sized + Operation 
{ 
    fn do_thing(&self) -> u32 { 
     self.x.operation() 
    } 
} 

impl<'a> Operation for &'a u32 { 
    fn operation(self) -> u32 { 
     *self 
    } 
} 

fn main() { 
    let container = Container { x: 1 }; 
    println!("{}", container.do_thing()); 
} 

druckt

1 
+1

Das ist großartig. Ich habe das Buch mehrere Male gelesen und HRTB war eine Quelle der Verwirrung für mich. Diese Antwort hat mir geholfen (und ich bin nicht der OP!). Danke noch einmal! –

+0

Sie sind nicht in dem Buch :(Sie werden in der zweiten Ausgabe sein –

+0

HRTB kann begrenzend sein. Die Grenze 'für <'a> & 'eine T: Operation' erfordert implizit 'für <'a> T:' a', im Grunde das' T: 'statisch' (enthält keine geliehenen Daten). – bluss