英文:
How to implement a Box-like `MyBox` that supports trait objects like `Vec<MyBox<dyn MyTrait>>`
问题
以下是已翻译的内容:
以下的 MyBox
结构与 Box
设置非常相似,但在结构体 Vec<MyBox<dyn MyTrait>>
中它却无法正常工作。然而,在 Box
中的 trait 对象的向量却能够正常工作,即 Vec<Box<dyn MyTrait>>
。
错误信息是
期望的结构体是
mybox::MyBox<dyn mybox::MyTrait>
找到的结构体是mybox::MyBox<mybox::MyStruct>
是什么让 Box
能够正确地进行类型检查?是 Box
实现了一个可以解决这个问题的 trait 吗?
use std::ptr::NonNull;
trait MyTrait {}
struct MyStruct {}
impl MyTrait for MyStruct {}
struct MyBox<T: ?Sized> {
value: NonNull<T>
}
impl<T> MyBox<T> {
pub fn new(value: T) -> MyBox<T> {
unsafe {
MyBox { value: NonNull::new_unchecked(Box::into_raw(Box::new(value))) }
}
}
}
/// 正常工作
fn main_box() {
let mut v: Vec<Box<dyn MyTrait>> = Vec::new();
let x: Box<MyStruct> = Box::new(MyStruct {});
v.push(x);
}
/// 存在类型错误
fn main_mybox() {
let mut v: Vec<MyBox<dyn MyTrait>> = Vec::new();
let x: MyBox<MyStruct> = MyBox::new(MyStruct {});
v.push(x);
}
我已经尝试模仿 Box<T>
的结构,但可能是我忽略了一个它实现的 trait。
英文:
The following MyBox
struct is setup extremely similarly to Box
, and yet it does not work with a vector of trait objects in the struct Vec<MyBox<dyn MyTrait>>
. However a vector of trait objects in a Box
works just fine, Vec<Box<dyn MyTrait>>
.
The error is
> expected struct mybox::MyBox<dyn mybox::MyTrait>
> found struct mybox::MyBox<mybox::MyStruct>
What is it about Box
that allows it to properly type check? Does Box
implement a trait that allows it to resolve?
use std::ptr::NonNull;
trait MyTrait {}
struct MyStruct {}
impl MyTrait for MyStruct {}
struct MyBox<T: ?Sized> {
value: NonNull<T>
}
impl<T> MyBox<T> {
pub fn new(value: T) -> MyBox<T> {
unsafe {
MyBox { value: NonNull::new_unchecked(Box::into_raw(Box::new(value))) }
}
}
}
/// Works just fine
fn main_box() {
let mut v: Vec<Box<dyn MyTrait>> = Vec::new();
let x: Box<MyStruct> = Box::new(MyStruct {});
v.push(x);
}
/// Has type error
fn main_mybox() {
let mut v: Vec<MyBox<dyn MyTrait>> = Vec::new();
let x: MyBox<MyStruct> = MyBox::new(MyStruct {});
v.push(x);
}
I have tried mimicking the structure of Box<T>
but there must be a trait that it implements that I am missing.
答案1
得分: 1
MyStruct
和 dyn MyTrait
是不同的类型,允许它们之间的强制转换的是 CoerceUnsized
对 Box<T, A>
到 Box<U, A>
的实现,但你缺少了这个实现。
#![feature(coerce_unsized, unsize)]
use std::marker::Unsize;
use std::ops::CoerceUnsized;
impl<T, U> CoerceUnsized<MyBox<U>> for MyBox<T>
where
T: Unsize<U> + ?Sized,
U: ?Sized {}
如你所见,目前需要两个功能来实现它,因此你必须使用夜间编译器来使用它。
如果你必须使用稳定的编译器,你可以在 Box
上执行强制转换,然后将其转换为 MyBox<dyn MyTrait>
:
impl<T: ?Sized> From<Box<T>> for MyBox<T> {
fn from(b: Box<T>) -> Self {
unsafe {
MyBox {
value: NonNull::new_unchecked(Box::into_raw(b)),
}
}
}
}
/// 存在类型错误
fn main_mybox() {
let mut v: Vec<MyBox<dyn MyTrait>> = Vec::new();
let b: Box<dyn MyTrait> = Box::new(MyStruct {}); // 强制转换发生在这里
let x: MyBox<dyn MyTrait> = b.into();
v.push(x);
}
英文:
MyStruct
and dyn MyTrait
are different types, what allows coercion from one to the other for a Box
is the CoerceUnsized
implementation of Box<T, A>
to Box<U, A>
which you're lacking.
#![feature(coerce_unsized, unsize)]
use std::marker::Unsize;
use std::ops::CoerceUnsized;
impl<T, U> CoerceUnsized<MyBox<U>> for MyBox<T>
where
T: Unsize<U> + ?Sized,
U: ?Sized {}
As you can see that requires 2 features to implement at the moment so you have to run a nightly compiler to use it.
If you have to use a stable compiler you could do the coercion on the Box
and turn that into MyBox<dyn MyTrait>
afterwards:
impl<T: ?Sized> From<Box<T>> for MyBox<T> {
fn from(b: Box<T>) -> Self {
unsafe {
MyBox {
value: NonNull::new_unchecked(Box::into_raw(b)),
}
}
}
}
/// Has type error
fn main_mybox() {
let mut v: Vec<MyBox<dyn MyTrait>> = Vec::new();
let b: Box<dyn MyTrait> = Box::new(MyStruct {}); // coercion happens here
let x: MyBox<dyn MyTrait> = b.into();
v.push(x);
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论