允许使用用户定义类型创建特征对象?
Allow trait object creation with user-defined type?
在 Rust 中,引用以及 Box<T>
、Rc<T>
和 Arc<T>
允许创建特征对象(例如,从 Box<Type>
到 Box<dyn Trait>
).但是有没有办法允许与用户定义的通用“智能指针”类型进行相同的转换?
例如,MyBox<T>
是 Box<T>
的精简包装器,但下面的代码会导致编译错误:
use std::io::Write;
pub fn main() {
let std_box: Box<Vec<u8>> = Box::new(Vec::new());
let std_dyn: Box<dyn Write> = std_box;
// ^ this conversion is allowed.
let my_box: MyBox<Vec<u8>> = MyBox { t: Box::new(Vec::new()) };
let my_dyn: MyBox<dyn Write> = my_box;
// ^ this conversion is not allowed.
}
struct MyBox<T: ?Sized> {
t: Box<T>,
}
error[E0308]: mismatched types
--> traits/src/trait_objs.rs:7:36
|
7 | let my_dyn: MyBox<dyn Write> = my_box;
| ---------------- ^^^^^^ expected trait object `dyn std::io::Write`, found struct `Vec`
| |
| expected due to this
|
= note: expected struct `MyBox<dyn std::io::Write>`
found struct `MyBox<Vec<u8>>`
不幸的是,看起来 Rust Stable 的答案是“你不需要”。 Rust 在允许隐式强制转换方面非常保守。特别是,从 the docs 中,我们看到了针对 Box
.
的规则
Coercion is allowed between the following types:
...
TyCtor(T
) to TyCtor(U
), where TyCtor(T
) is one of
&T
&mut T
*const T
*mut T
Box<T>
and where U
can be obtained from T
by unsized coercion.
相关未定大小的强制规则是
T
to dyn U
, when T
implements U + Sized
, and U
is object safe.
那里没有太多用于特殊外壳的空间,至少在当前版本的 Rust 中没有。
但是, 如果您愿意深入了解 Nightly-only 功能,那么您会得到令人兴奋的 CoerceUnsized
trait,其预期用例是……智能指向像 Box
那样强制的东西。
#![feature(unsize, coerce_unsized)]
use std::ops::CoerceUnsized;
use std::marker::Unsize;
impl<T, U> CoerceUnsized<MyBox<U>> for MyBox<T> where T: Unsize<U>, U: ?Sized {}
这告诉 Rust 如果 T
与 U
“基本相同”,我们可以将 MyBox<T>
强制转换为 MyBox<U>
,以获得“基本相同”的适当定义”。实现不需要任何功能;特质 impl
只需要存在即可。
在 Rust 中,引用以及 Box<T>
、Rc<T>
和 Arc<T>
允许创建特征对象(例如,从 Box<Type>
到 Box<dyn Trait>
).但是有没有办法允许与用户定义的通用“智能指针”类型进行相同的转换?
例如,MyBox<T>
是 Box<T>
的精简包装器,但下面的代码会导致编译错误:
use std::io::Write;
pub fn main() {
let std_box: Box<Vec<u8>> = Box::new(Vec::new());
let std_dyn: Box<dyn Write> = std_box;
// ^ this conversion is allowed.
let my_box: MyBox<Vec<u8>> = MyBox { t: Box::new(Vec::new()) };
let my_dyn: MyBox<dyn Write> = my_box;
// ^ this conversion is not allowed.
}
struct MyBox<T: ?Sized> {
t: Box<T>,
}
error[E0308]: mismatched types
--> traits/src/trait_objs.rs:7:36
|
7 | let my_dyn: MyBox<dyn Write> = my_box;
| ---------------- ^^^^^^ expected trait object `dyn std::io::Write`, found struct `Vec`
| |
| expected due to this
|
= note: expected struct `MyBox<dyn std::io::Write>`
found struct `MyBox<Vec<u8>>`
不幸的是,看起来 Rust Stable 的答案是“你不需要”。 Rust 在允许隐式强制转换方面非常保守。特别是,从 the docs 中,我们看到了针对 Box
.
Coercion is allowed between the following types:
...
TyCtor(
T
) to TyCtor(U
), where TyCtor(T
) is one of
&T
&mut T
*const T
*mut T
Box<T>
and where
U
can be obtained fromT
by unsized coercion.
相关未定大小的强制规则是
T
todyn U
, whenT
implementsU + Sized
, andU
is object safe.
那里没有太多用于特殊外壳的空间,至少在当前版本的 Rust 中没有。
但是, 如果您愿意深入了解 Nightly-only 功能,那么您会得到令人兴奋的 CoerceUnsized
trait,其预期用例是……智能指向像 Box
那样强制的东西。
#![feature(unsize, coerce_unsized)]
use std::ops::CoerceUnsized;
use std::marker::Unsize;
impl<T, U> CoerceUnsized<MyBox<U>> for MyBox<T> where T: Unsize<U>, U: ?Sized {}
这告诉 Rust 如果 T
与 U
“基本相同”,我们可以将 MyBox<T>
强制转换为 MyBox<U>
,以获得“基本相同”的适当定义”。实现不需要任何功能;特质 impl
只需要存在即可。