我有以下代码
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`
当Sized
没有将Rng
强加于Box<T>
时,我不明白为什么T
需要abstract class Foo {
def f(): ??? = { ... }
}
class Bar extends Foo {
...
}
class Baz extends Foo {
...
}
。
答案 0 :(得分:5)
关于Sized
特征和约束的更多信息 - 它是一个相当特殊的特征,对于每个函数都是implicitly added,这就是为什么你没有看到它在原型中列出的原因对于Box::new
:
fn new(x: T) -> Box<T>
请注意,它需要x
值(或移动),所以你需要知道甚至调用函数有多大。
相反,Box
类型本身不需要Sized
;它使用(再次特殊)特征绑定?Sized
,这意味着&#34;选择退出默认的Sized
绑定&#34;:
pub struct Box<T> where T: ?Sized(_);
如果你仔细观察,有一种方法可以创建一个带有unsized类型的Box
:
impl<T> Box<T> where T: ?Sized
....
unsafe fn from_raw(raw: *mut T) -> Box<T>
因此,从不安全的代码中,您可以从原始指针创建一个。从那以后,所有正常的事情都有效。
答案 1 :(得分:3)
问题其实很简单:你有一个特质对象,你对这个特质对象知道的唯一两件事是:
当您请求将此对象移动到其他内存位置(此处位于堆上)时,您缺少一条关键信息:其大小。
你怎么知道应该保留多少内存?要移动多少位?
当对象为Sized
时,此信息在编译时是已知的,因此编译器会为您“注入”它。但是,在特征对象的情况下,这些信息是未知的(遗憾的是),因此这是不可能的。
提供这些信息并提供多态移动/克隆是非常有用的,但这还不存在,我不记得到目前为止的任何提议,我不知道成本是多少(在维护,运行时惩罚等方面......)。
答案 2 :(得分:1)
我也想发布答案,处理这种情况的一种方法是
fn with_rng<TRand: Rng>(rng: &TRand) -> Self {
let r = Box::new(*rng);
Randomizer { rand: r }
}
Rust的单态性将创建with_rng
以具体大小类型替换TRand
的必要实现。此外,您可以添加要求TRand
为Sized
的特征限制。