当T是特征对象时,如何创建Box <T>?

And*_*eas 3 rust trait-objects

我有以下代码

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() {}
Run Code Online (Sandbox Code Playgroud)

它抱怨说

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`
Run Code Online (Sandbox Code Playgroud)

我不明白为什么它需要SizedRng时候Box<T>不征收此上T.

Chr*_*son 5

关于Sized特征和边界的更多信息- 它是一个相当特殊的特征,它隐含地添加到每个函数中,这就是为什么你没有在原型中看到它列出的原因Box::new:

fn new(x: T) -> Box<T>
Run Code Online (Sandbox Code Playgroud)

请注意,它需要x按值(或移动),因此您需要知道甚至调用函数有多大.

与此相反,Box类型本身并没有要求Sized; 它使用(再次特殊)特征绑定?Sized,这意味着"退出默认Sized绑定":

pub struct Box<T> where T: ?Sized(_);
Run Code Online (Sandbox Code Playgroud)

如果您仔细查看,有一种方法可以Box使用unsized类型创建:

impl<T> Box<T> where T: ?Sized
....
    unsafe fn from_raw(raw: *mut T) -> Box<T>
Run Code Online (Sandbox Code Playgroud)

因此,从不安全的代码中,您可以从原始指针创建一个.从那时起,所有正常的事情都有效.