考虑这样的代码:
trait Foo {
fn foo(&self);
}
fn consume_func(b: Box<Box<Foo>>) {
unimplemented!();
}
fn produce_func() -> Box<Box<Foo + Send>> {
unimplemented!();
}
fn main() {
let b = produce_func();
consume_func(b);
}
它不编译:
error[E0308]: mismatched types
--> src/main.rs:24:18
|
24 | consume_func(b);
| ^ expected trait `Foo`, found trait `Foo + std::marker::Send`
|
= note: expected type `std::boxed::Box<std::boxed::Box<Foo + 'static>>`
found type `std::boxed::Box<std::boxed::Box<Foo + std::marker::Send>>`
双Box
是一种从Box<Trait>
为 C 库提供void *
指针的方法。由于胖指针,我无法将Box<Foo>
转换为void *
。
我不能更改consume_func
,我宁愿不使用unsafe
或额外的分配。
这里有一种方法:取消引用b
(将其"取消装箱"到Box<Foo + Send>
),然后立即将其包装在另一个Box<T>
中,允许编译器推断出正确的T
(在本例中为Box<Foo>
)。
consume_func(Box::new(*b));
这是有效的,因为Box<Foo + Send>
可以自动强制Box<Foo>
,但Box<Box<Foo + Send>>
不能被强制Box<Box<Foo>>
。
虽然你已经声明你不能改变consume_func
,但其他有类似问题的人可以改变它以接受泛型:
fn consume_func<F: Foo + ?Sized>(b: Box<Box<F>>) {
unimplemented!();
}