2016-08-29 1 views
1

Ich habe den folgenden CodeWie erstellen Sie eine Box <T>, wenn T ein Objekt ist?

extern crate rand; 
use rand::Rng; 

pub struct Randomizer { 
    rand: Box<Rng>, 
} 

impl Randomizer { 
    fn new() -> Self { 
     let mut r = Box::new(rand::thread_rng()); // works 
     let mut cr = Randomizer { rand: r }; 
     cr 
    } 

    fn with_rng(rng: &Rng) -> Self { 
     let mut r = Box::new(*rng); // doesn't work 
     let mut cr = Randomizer { rand: r }; 
     cr 
    } 
} 

fn main() {} 

Sie wirft

error[E0277]: the trait bound `rand::Rng: std::marker::Sized` is not satisfied 
    --> src/main.rs:16:21 
    | 
16 |   let mut r = Box::new(*rng); 
    |      ^^^^^^^^ `rand::Rng` does not have a constant size known at compile-time 
    | 
    = help: the trait `std::marker::Sized` is not implemented for `rand::Rng` 
    = note: required by `<std::boxed::Box<T>>::new` 

Ich verstehe nicht, warum es Sized auf Rng erfordert, wenn Box<T> dies nicht auf T verhängen.

+1

Dies hat eigentlich keine Beziehung, whatsover, mit der Tatsache, dass Sie später dies in einem Mitglied speichern, so ist der Titel ziemlich ungenau und wird nicht weiter Suchern viel helfen. Wenn jemand eine Idee für eine bessere Idee hat ... –

+0

Kennen Sie [Merkmalsobjekte] (https://doc.rust-lang.org/book/trait-objects.html)? – kennytm

+0

@MatthieuM. Sie haben Recht, dass der Titel verbessert werden muss. – Andreas

Antwort

4

Mehr zu dem Sized Charakterzug und gebunden - es ist ein ganz besonderes Merkmal, das implicitly added zu jeder Funktion ist, weshalb man es im Prototyp für Box::new nicht aufgeführt sehen:

fn new(x: T) -> Box<T> 

Beachten Sie, dass Es dauert x nach Wert (oder verschieben), so dass Sie wissen müssen, wie groß es ist, die Funktion sogar aufzurufen.

Im Gegensatz dazu benötigt der Box-Typ selbst nicht erfordert Sized; es nutzt das (wieder Sonder) Merkmal ?Sized gebunden, die „Opt-out von der Standard-Sized gebunden“ bedeutet:

pub struct Box<T> where T: ?Sized(_); 

Wenn Sie durch suchen, gibt es eine Möglichkeit, ein Box mit einem unsized Art zu schaffen:

so aus unsicheren Code, können Sie einen von einem rohen Zeiger erstellen. Von da an funktionieren alle normalen Dinge.

3

Das Problem ist eigentlich ganz einfach: Sie können ein Merkmal Objekt haben, und die nur zwei Dinge, die Sie über dieses Merkmal Objekt kennen, sind:

  • seine Liste der verfügbaren Methoden
  • der Zeiger auf seine Daten

Wenn Sie anfordern, um dieses Objekt zu einem anderen Speicherort zu bewegen (hier auf dem Heap), die Sie vermissen ein entscheidend Stück Information: seine Größe.

Wie werden Sie wissen, wie viel Speicher reserviert werden sollte? Wie viele Bits müssen bewegt werden?

Wenn ein Objekt Sized ist, ist diese Information zur Kompilierzeit bekannt, so dass der Compiler sie für Sie "eingibt". Im Falle eines Merkmalsobjekts ist diese Information jedoch (leider) unbekannt, und deshalb ist dies nicht möglich.

Es wäre sehr nützlich, diese Informationen zur Verfügung zu stellen und einen polymorphen Zug/Klon zur Verfügung zu haben, aber das gibt es noch nicht und ich kann mich an keinen Vorschlag dafür erinnern und ich habe keine Ahnung was die Kosten wären (in Bezug auf Wartung, Laufzeitstrafe, ...).

1

Ich möchte auch die Antwort zu schreiben, dass ein Weg, um mit dieser Situation umgehen

fn with_rng<TRand: Rng>(rng: &TRand) -> Self { 
    let r = Box::new(*rng); 
    Randomizer { rand: r } 
} 

Rust ist Monomorphie die notwendige Umsetzung der with_rng ersetzt TRand durch eine konkrete Größe Typ erstellen. Zusätzlich können Sie eine Merkmalsgrenze hinzufügen, die TRand zu Sized erfordert.

Verwandte Themen