我很难理解框式特征的价值是如何形成的。考虑以下代码:
trait Fooer {
fn foo(&self);
}
impl Fooer for i32 {
fn foo(&self) { println!("Fooer on i32!"); }
}
fn main() {
let a = Box::new(32); // works, creates a Box<i32>
let b = Box::<i32>::new(32); // works, creates a Box<i32>
let c = Box::<Fooer>::new(32); // doesn't work
let d: Box<Fooer> = Box::new(32); // works, creates a Box<Fooer>
let e: Box<Fooer> = Box::<i32>::new(32); // works, creates a Box<Fooer>
}
很明显,变体a和b非常有用。但是,变体c没有这样做,可能是因为new
函数仅采用相同类型的值,而自Fooer != i32
以来就不是这种情况。 d和e的变体,使我怀疑正在执行从Box<i32>
到Box<Fooer>
的某种自动转换。
所以我的问题是:
Box<Fooer>
创建i32
?如果没有:为什么不呢?答案 0 :(得分:8)
但是,变体c却没有,可能是因为
new
函数仅采用相同类型的值,而自Fooer != i32
之后就没有这种情况。
不,这是因为new
没有{em> 功能。在documentation中:
Box<dyn Fooer>
impl<T> Box<T>
pub fn new(x: T) -> Box<T>
上的大多数方法都允许Box<T>
,但是T: ?Sized
是在new
中定义的,没有约束impl
。 means仅在T: ?Sized
是已知大小的类型时才可以调用Box::<T>::new
。 T
没有大小,因此根本没有dyn Fooer
的调用方法。
实际上,该方法不存在。为了装箱,您需要知道它的大小。为了将其传递给函数,您需要知道其大小。为了使变量包含某些内容,它必须具有大小。像new
这样的未定义类型只能存在于“胖指针”之后,即指向对象的指针和指向该对象的dyn Fooer
实现的指针。 / p>
您如何获得胖指针?您从细指针开始,然后强制。这就是这两行中发生的事情:
Fooer
let d: Box<Fooer> = Box::new(32); // works, creates a Box<Fooer>
let e: Box<Fooer> = Box::<i32>::new(32); // works, creates a Box<Fooer>
返回一个Box::new
,然后它是coerced至Box<i32>
。您可以认为这是一次转换,但是Box<Fooer>
并未更改;编译器所做的全部工作就是在其上附加一个指针,然后忘记其原始类型。 rodrigo's answer详细介绍了这种强制的语言级机制。
希望所有这些都能解释为什么答案
是否可以直接从
Box
创建Box<Fooer>
?
为“否”:必须先将i32
装箱,然后才能清除其类型。这是您不能写i32
的相同原因。
答案 1 :(得分:5)
我将尝试解释您的代码中发生了哪些转换(强制)。
之间有一个名为Unsize
的标记特征:
未调整大小适用于:
T
是Unsize<Trait>
时的T: Trait
。- [...]
此特征AFAIK不直接用于强制。而是使用CoerceUnsized
。在许多情况下都可以实现此特征,其中有些是可以预期的,例如:
impl<'a, 'b, T, U> CoerceUnsized<&'a U> for &'b T
where
'b: 'a,
T: Unsize<U> + ?Sized,
U: ?Sized
用于将&i32
强制转换为&Fooer
。
此特征有趣但不太明显的实现会影响您的代码:
impl<T, U> CoerceUnsized<Box<U>> for Box<T>
where
T: Unsize<U> + ?Sized,
U: ?Sized
这与Unsize
标记的定义可以理解为:如果U
是一个特征并且T
实现了U
,则Box<T>
可以强制进入Box<U>
。
关于您的最后一个问题:
是否可以直接从
Box<Fooer>
创建i32
?如果不是:为什么不呢?
我不知道。问题在于Box::new(T)
要求使用大小值,因为传递的值已移动到框中,并且未移动的值无法移动。
我认为,最简单的方法是简单地编写:
let c = Box::new(42) as Box<Fooer>;
也就是说,您创建了一个正确类型的Box
,然后强制使用未缩放的大小(请注意,它看起来与您的d
示例非常相似)。