使用Result::map和Box时无法推断类型

4
为什么这个代码无法编译?
trait T {}

fn f<U: 'static + T, V, E>(f2: V) -> impl Fn() -> Result<Box<dyn T>, E>
where
    V: Fn() -> Result<U, E>,
{
    move || -> Result<Box<dyn T>, E> { f2().map(Box::new) }
}

错误信息如下:
error[E0308]: mismatched types
 --> src/lib.rs:7:40
  |
7 |     move || -> Result<Box<dyn T>, E> { f2().map(Box::new) }
  |                                        ^^^^^^^^^^^^^^^^^^ expected trait T, found type parameter
  |
  = note: expected type `std::result::Result<std::boxed::Box<(dyn T + 'static)>, _>`
             found type `std::result::Result<std::boxed::Box<U>, _>`
  = help: type parameters must be constrained to match other types
  = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters

这个版本可以使用:

trait T {}

fn f<U: 'static + T, V, E>(f2: V) -> impl Fn() -> Result<Box<dyn T>, E>
where
    V: Fn() -> Result<U, E>,
{
    move || -> Result<Box<dyn T>, E> {
        match f2() {
            Ok(result) => Ok(Box::new(result)),
            Err(e) => Err(e),
        }
    }
}

我的观点是,(dyn T + 'static)U 是相同的;我是对的吗?

我正在使用的版本是 rustc 1.39.0-nightly (f0b58fcf0 2019-09-11)

1个回答

7

这是一个限制条件,我不知道它是否会在某一天编译。原因是Rust不知道如何在两个Result类型之间进行转换,(dyn T + 'static)U是完全不同的东西。如果可以接受,您可以执行f2().map(|x| Box::new(x) as _)

这种强制转换将允许编译器在将其放入结果之前将U转换为(dyn T + 'static),我们不需要显式指定转换类型,编译器推理会为我们完成(大多数情况下)。

通过将实现该trait的具体类型的指针转换为trait对象来获取trait对象(例如,&x as &Foo)

请参见书籍中的动态调度部分(在新书中未找到任何信息)。


这里需要一些解释,说明魔法“as _”是如何工作的。编译器如何决定在这种情况下“_”代表什么。 - Michael Anderson
@MichaelAnderson 希望这样更清楚了,不幸的是这个问题没有太多的参考资料。 - Stargateur
谢谢你澄清这个问题。我知道编译器会在一些地方进行类型推断,只是没想到它会作为 as X 的一部分。看起来这是一个非常有用的功能。可惜它没有更好的文档说明。 - Michael Anderson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接