首页 > 解决方案 > 允许使用用户定义的类型创建特征对象?

问题描述

在 Rust 中,引用以及Box<T>Rc<T>Arc<T>允许创建特征对象(例如, fromBox<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>>`

标签: rusttraits

解决方案


不幸的是,Rust Stable 的答案似乎是“你不知道”。Rust 非常保守,它允许隐式强制。特别是,从docs中,我们看到了适用于Box.

允许在以下类型之间进行强制转换:

...

  • TyCtor( T) 到 TyCtor( U),其中 TyCtor( T) 是其中之一

    • &T
    • &mut T
    • *const T
    • *mut T
    • Box<T>

并且U可以T通过unsized coercion从哪里获得。

其中相关的无大小强制规则是

  • Tto dyn U, whenT实现U + Sized, 并且U对象安全的。

那里没有太多空间可以放置特殊的外壳,至少在当前版本的 Rust 中没有。

但是,如果您愿意深入了解 Nightly 独有的功能,那么您将获得令人兴奋的CoerceUnsizedtrait,其预期的用例是......指向会强制执行的事物的智能指针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 我们可以强制if is "basically the same" as ,MyBox<T>以获得“基本相同”的适当定义。实现不需要函数;特质只需要存在。MyBox<U>TUimpl


推荐阅读