【问题标题】:Why does using Option::map to Box::new a trait object not work?为什么使用 Option::map 到 Box::new 一个特征对象不起作用?
【发布时间】:2018-02-19 10:25:41
【问题描述】:
trait FooTrait {}

struct FooStruct;

impl FooTrait for FooStruct {}

fn main() {
    let maybe_struct: Option<dyn FooStruct> = None;

    //  Does not compile
    let maybe_trait: Option<Box<dyn FooTrait>> = maybe_struct.map(Box::new);

    // Compiles fine
    let maybe_trait: Option<Box<dyn FooTrait>> = match maybe_struct {
        Some(s) => Some(Box::new(s)),
        None => None,
    };
}
error[E0404]: expected trait, found struct `FooStruct`
 --> src/main.rs:9:34
  |
9 |     let maybe_struct: Option<dyn FooStruct> = None;
  |                                  ^^^^^^^^^ not a trait

Rustc 1.23.0。为什么第一种方法不能编译?我是否遗漏了一些明显的东西,或者……嗯?

【问题讨论】:

    标签: rust trait-objects


    【解决方案1】:

    Box::new 仅适用于大小类型;也就是说,它接受一个大小类型为T 的值并返回Box&lt;T&gt;。在某些地方,Box&lt;T&gt; 可以将coerced 转换为Box&lt;U&gt;(如果T: Unsize&lt;U&gt;)。

    这种强制不会发生在.map(Box::new),但会发生在Some(Box::new(s));后者与Some(Box::new(s) as Box&lt;FooTrait&gt;)基本相同。

    您可以(每晚)创建自己的盒子构造函数,它返回大小不一的盒子,如下所示:

    #![feature(unsize)]
    
    fn box_new_unsized<T, U>(v: T) -> Box<U>
    where
        T: ::std::marker::Unsize<U>,
        U: ?Sized,
    {
        Box::<T>::new(v)
    }
    

    并像.map(box_new_unsized) 一样使用它。见Playground

    【讨论】:

    • 啊哈,我错过了 as Box&lt;FooTrait&gt; 隐含在幕后发生的事情,以及(回想起来很明显)asNOT 无操作的事实,创建 trait 对象不仅仅是玩类型归属,而是实际操作。如果我想使用.map,我可以明确地let maybe_trait = maybe_struct.map(|x| Box::new(x) as Box&lt;FooTrait&gt;);。我还得完全消化强制,Unsize 和朋友们。谢谢。
    • @TomášDvořák 顺便说一句:您通常可以在 as 表达式中省略目标类型,如下所示:|x| Box::new(x) as _
    • 这个as Box&lt;FooTrait&gt; 语法也可以帮助我解决与这里提出的问题完全不同的上下文。
    猜你喜欢
    • 1970-01-01
    • 2013-11-02
    • 2013-03-03
    • 2019-09-15
    • 2022-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-30
    相关资源
    最近更新 更多