簡體   English   中英

你如何創建一個盒子<dyn Trait> ,還是一般的盒裝未大小值?

[英]How do you create a Box<dyn Trait>, or a boxed unsized value in general?

我有以下代碼

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() {}

它抱怨說

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`

我不明白為什么當Box<T>沒有將其強加給T時,它需要在RngRng Sized

關於Sized trait 和 bound 的更多信息 - 這是一個相當特殊的 trait,它被隱式添加到每個函數中,這就是為什么你看不到它在Box::new的原型中列出的原因:

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

請注意,它按值(或移動)取x ,因此您甚至需要知道調用該函數的大小。

相比之下, Box型本身並不需要Sized ; 它使用(再次特殊的)特征綁定?Sized ,這意味着“選擇退出默認的Sized綁定”:

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

如果你仔細看看,有一種方法可以創建一個無大小類型的Box

impl<T> Box<T> where T: ?Sized
....
    unsafe fn from_raw(raw: *mut T) -> Box<T>

因此,從不安全的代碼中,您可以從原始指針創建一個。 從那時起,一切正常。

問題其實很簡單:你有一個 trait 對象,關於這個 trait 對象你只知道兩件事:

  • 它的可用方法列表
  • 指向其數據的指針

當您請求將此對象移動到不同的內存位置(在堆上)時,您會丟失一個關鍵信息:它的大小

你怎么知道應該保留多少內存? 要移動多少位?

當對象為Sized ,此信息在編譯時是已知的,因此編譯器會為您“注入”它。 然而,在 trait-object 的情況下,這個信息是未知的(不幸的是),因此這是不可能的。

使這些信息可用並提供多態移動/克隆可用將非常有用,但這還不存在,到目前為止我不記得有任何建議,我不知道成本是多少(就維護,運行時間懲罰,...)。

我也想發布答案,處理這種情況的一種方法是

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

Rust 的單態性將創建with_rng的必要實現,用具體大小的類型替換TRand 此外,您可以添加需要TRandSized的 trait bound。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM