我正在try 从函数返回特征对象的装箱结果.我的函数返回(似乎)满足该特征对象的正确类型.然而,编译器说类型不匹配.以下是我的代码:

use anyhow::Result;

#[derive(Debug)]
struct Bar {
    a: i32,
    b: i32,
}

trait Wrap {}

struct Wrapper1<'a> {
    bar: &'a Bar,
}

impl<'a> Wrapper1<'a> {
    fn new(bar: &'a Bar) -> Result<Self> {
        Ok(Self { bar })
    }
}

impl<'a> Wrap for Wrapper1<'a> {}

struct Wrapper2<'a> {
    bar: &'a Bar,
}

impl<'a> Wrapper2<'a> {
    fn new(bar: &'a Bar) -> Result<Self> {
        Ok(Self { bar })
    }
}

impl<'a> Wrap for Wrapper2<'a> {}

fn wrap<'a>(i: i32, bar: &'a Bar) -> Result<Box<dyn Wrap + 'a>> {
    if i % 2 == 0 {
        Wrapper1::new(bar).map(Box::new)
    } else {
        Wrapper2::new(bar).map(Box::new)
    }
}

这就是我得到的错误.

error[E0308]: mismatched types
  --> src/main.rs:37:9
   |
35 | fn wrap<'a>(i: i32, bar: &'a Bar) -> Result<Box<dyn Wrap + 'a>> {
   |                                      -------------------------- expected `Result<Box<(dyn Wrap + 'a)>, anyhow::Error>` because of return type
36 |     if i % 2 == 0 {
37 |         Wrapper1::new(bar).map(Box::new)
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Result<Box<dyn Wrap>, Error>`, found `Result<Box<Wrapper1<'_>>, Error>`
   |
   = note: expected enum `Result<Box<(dyn Wrap + 'a)>, _>`
              found enum `Result<Box<Wrapper1<'_>>, _>`
help: use `?` to coerce and return an appropriate `Err`, and wrap the resulting value in `Ok` so the expression remains of type `Result`
   |
37 |         Ok(Wrapper1::new(bar).map(Box::new)?)
   |         +++                                ++

error[E0308]: mismatched types
  --> src/main.rs:39:9
   |
35 | fn wrap<'a>(i: i32, bar: &'a Bar) -> Result<Box<dyn Wrap + 'a>> {
   |                                      -------------------------- expected `Result<Box<(dyn Wrap + 'a)>, anyhow::Error>` because of return type
...
39 |         Wrapper2::new(bar).map(Box::new)
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Result<Box<dyn Wrap>, Error>`, found `Result<Box<Wrapper2<'_>>, Error>`
   |
   = note: expected enum `Result<Box<(dyn Wrap + 'a)>, _>`
              found enum `Result<Box<Wrapper2<'_>>, _>`
help: use `?` to coerce and return an appropriate `Err`, and wrap the resulting value in `Ok` so the expression remains of type `Result`
   |
39 |         Ok(Wrapper2::new(bar).map(Box::new)?)
   |         +++                                ++

For more information about this error, try `rustc --explain E0308`.
error: could not compile `foo` due to 2 previous errors

编译器建议这样包装我的表达式,这确实有效.

Ok(Wrapper2::new(bar).map(Box::new)?)
+++                                ++

然而,我不明白为什么这是必要的,因为它似乎使类型完全相同.它也不太符合人体工程学.

推荐答案

Box::new()的签名是fn<T>(T) -> Box<T>.如果返回&Bar,则返回Box<&Bar>.不是Box<dyn Wrap>,即使你真的想要.

你真正需要的是two步:首先,把&Bar包进Box,然后强迫它变成Box<dyn Wrap>.Box::new()能够而且将会心甘情愿地迈出第一步,但它就是做不到第二步.

编译器也不能将Result<Box<&Bar>>转换为Result<Box<dyn Wrap>>,因为强制是不可传递的:Box<&Bar>可以被强制为Box<dyn Wrap>这一事实并不意味着Result<Box<&Bar>>可以被强制为Result<Box<dyn Wrap>>.

编译器建议的是展开Result:通过这种方式,当您提取Ok值时,编译器可以强制将Box<&Bar>转换为Box<dyn Wrap>,然后用Result包装that,结果为Result<Box<dyn Wrap>>.

另一种方法是将Box::new()替换为执行强制的自定义闭包:

fn wrap<'a>(i: i32, bar: &'a Bar) -> Result<Box<dyn Wrap + 'a>> {
    if i % 2 == 0 {
        Wrapper1::new(bar).map(|v| Box::new(v) as _)
    } else {
        Wrapper2::new(bar).map(|v| Box::new(v) as _)
    }
}

在这里,as _是对编译器执行强制的提示.

Rust相关问答推荐

为什么对不可复制数据的引用的取消引用没有O权限来避免Rust中的双重释放?

是否可以为`T:Copy`执行`T. clone`的测试

使用Clap时如何将String作为Into Str参数传递?

在决定使用std::Sync::Mutex还是使用Tokio::Sync::Mutex时,操作系统线程调度是考虑因素吗?

类型批注需要静态生存期

在0..1之间将U64转换为F64

为什么BufReader实际上没有缓冲短寻道?

在 Rust 中,在需要引用 self 的 struct 体方法中使用闭包作为 while 循环条件

实现 Deref 的 struct 可以返回对外部数据的引用吗?

Rust,如何从 Rc> 复制内部值并返回它?

提取指向特征函数的原始指针

Nom 解析器无法消耗无效输入

如何为整数切片定义一个带有额外函数的特性别名?

Rust 中的 Option as_ref 和 as_deref 有什么不同

为什么分配对变量的引用使我无法返回它

制作嵌套迭代器的迭代器

为什么-x试图解析为文字并在声明性宏中失败?

如何在没有 `make_contiguous()` 的情况下对 VecDeque 进行排序或反转?

A 有一个函数,它在 Option<> 类型中时无法编译,但在 Option<> 类型之外会自行编译.为什么?

令人困惑的错误消息? (解包运算符)