< 返回版块

viruscamp 发表于 2021-04-22 20:36

Tags:tokio 类型推断

use tokio::net::TcpListener;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    match TcpListener::bind(("127.0.0.1:20000")).await {
        Ok(listener)  => {}
        Err(err) => {
            //return Err(Box::new(err)); // 当有 #[tokio::main] 会出错
            //return Err(Box::<dyn std::error::Error>::new(err)); // 编译错误
            let err: Box<dyn std::error::Error> = Box::new(err); // 可以,跟上一行有什么不同?
            return Err(err);
        }
    }
    return Ok(());
}
  1. 当有 #[tokio::main] 时 return Err(Box::new(err)); 类型推断出错
13 | #[tokio::main]
   | ^^^^^^^^^^^^^^ expected trait object `dyn std::error::Error`, found struct `std::io::Error`
14 | async fn main() -> Result<(), Box<dyn std::error::Error>> {
   |                 -------------------------------------- expected `Result<(), Box<(dyn std::error::Error + 'static)>>` because of return type
   |
   = note: expected enum `Result<_, Box<(dyn std::error::Error + 'static)>>`
              found enum `Result<_, Box<std::io::Error>>`
   = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)
  1. return Err(Box::::new(err)); turbofish 不能用在 dyn trait ?
error[E0599]: the function or associated item `new` exists for struct `Box<dyn std::error::Error>`, but its trait bounds were not satisfied
  --> http-server-tokio\src\main.rs:19:54
   |
19 |             return Err(Box::<dyn std::error::Error>::new(err));
   |                                                      ^^^ function or associated item cannot be called on `Box<dyn std::error::Error>` due to unsatisfied trait bounds
   | 
  ::: D:\rust\rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib/rustlib/src/rust\library\std\src\error.rs:54:1
   |
54 | pub trait Error: Debug + Display {
   | -------------------------------- doesn't satisfy `dyn std::error::Error: Sized`
   |
   = note: the following trait bounds were not satisfied:
           `dyn std::error::Error: Sized`

评论区

写评论
作者 viruscamp 2021-04-23 09:14

大概都有解释了

  1. 当有 #[tokio::main] 时 return Err(Box::new(err)); 类型推断出错 从 https://docs.rs/tokio/1.5.0/tokio/attr.main.html#using-the-multi-thread-runtime 可以看出#[tokio::main]的转换方式,导致多了一层未指明返回类型的闭包。
#[tokio::main]
async fn main() -> Result<(), {
    println!("Hello world");
    Ok(())
}
fn main() {
    tokio::runtime::Builder::new_multi_thread()
        .enable_all()
        .build()
        .unwrap()
        .block_on(async {
            println!("Hello world");
            Ok(())
        })
}
  1. return Err(Box::::new(err)); turbofish 不能用在 dyn trait ?

创建 Box 不能用 new 只能类型转换

return Err(Box::new(err).into());
return Err(Box::new(err) as _);
return Err(Box::new(err) as Box<dyn std::error::Error>);
Err(Box::new(err))?;

--
👇
johnmave126: 因为trait object不等于struct,类型不一样

trait object本质上是一个fat pointer,Box<dyn Error>包含一个指向具体struct的指针和一个vtable指针。err是一个具体的在栈上的struct。所以正确使用需要显式转换,比如

return Err(Box::new(err).into());

或者

return Err(Box::new(err) as _);

甚至于

Err(Box::new(err))?;

都是可以的

johnmave126 2021-04-23 03:58

因为trait object不等于struct,类型不一样

trait object本质上是一个fat pointer,Box<dyn Error>包含一个指向具体struct的指针和一个vtable指针。err是一个具体的在栈上的struct。所以正确使用需要显式转换,比如

return Err(Box::new(err).into());

或者

return Err(Box::new(err) as _);

甚至于

Err(Box::new(err))?;

都是可以的

Grobycn 2021-04-22 21:15

第一个问题,看报错信息,应该是生命周期的问题。我也不太明白。

第二个问题,如果特别标注 T: ?Sized 放宽限制, 默认只为编译时期能确定占用内存大小的类型实现方法,dyn这种trait object没法在编译时确定内存大小, 所以 Box::new 没有为 dyn Error 实现。

1 共 3 条评论, 1 页