A 具有一个函数,该函数在 Option<> 类型内时不会编译,但在 Option<> 类型外会自行编译。为什么?

Fre*_*ors 4 rust

我有这个功能:

pub async fn player(&self, id: &str) -> Result<Option<Box<dyn AsyncRead + Send>>> {
    // use id here...
    let file = tokio::fs::File::open("player.pdf").await?;
    let res = Some(Box::new(file));
    Ok(res)
}
Run Code Online (Sandbox Code Playgroud)

它不起作用:

error[E0308]: mismatched types
    |
46  |         Ok(res)
    |         -- ^^^ expected trait object `dyn tokio::io::AsyncRead`, found struct `tokio::fs::File`
    |         |
    |         arguments to this enum variant are incorrect
    |
    = note: expected enum `std::option::Option<std::boxed::Box<dyn tokio::io::AsyncRead + std::marker::Send>>`
               found enum `std::option::Option<std::boxed::Box<tokio::fs::File>>`
note: tuple variant defined here
   --> C:\Users\Fred\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib/rustlib/src/rust\library\core\src\result.rs:508:5
    |
508 |     Ok(#[stable(feature = "rust1", since = "1.0.0")] T),
    |     ^^
Run Code Online (Sandbox Code Playgroud)

但如果我删除该Option<>部分,它就会起作用。为什么?

Apl*_*123 9

从本质上讲,您的问题可以归结为为什么这些函数之一可以编译,而另一个则不能:

fn compiles() -> Box<dyn std::fmt::Debug> {
    let b: Box<&str> = Box::new("foo");
    b
}

fn doesnt_compile() -> Option<Box<dyn std::fmt::Debug>> {
    let b: Option<Box<&str>> = Some(Box::new("foo"));
    b
}
Run Code Online (Sandbox Code Playgroud)

这里的关键是 和Box<T>Box<dyn Trait>具有不同内存表示的不同类型,即使T实现了Trait. 通常,Rust 很乐意隐式转换Box<T>Box<dyn Trait>,但是当 位于另一种类型内部时,这是无法完成的Box,因为它现在是非原始转换(就像为什么不能转换Option<u8>为一样Option<u16>)。

有几种方法可以解决这个问题。您可以尝试注释res( ) 或转换( )let res: Option<Box<dyn AsyncRead + Send>> = ...的结果。在许多情况下,也可以完全省略类型并只写,但我不确定这是否适用于这种情况。Box::newlet res = Some(Box::new(file) as Box<dyn AsyncRead + Send>)let res = Some(Box::new(file) as _)