rust - 为什么使用 Into::into 解析字符串映射结果无法推断类型?

标签 rust type-inference

以下 ( playground link )

#[derive(Debug)]
struct MyError();

impl From<::std::net::AddrParseError> for MyError {
    fn from(_e: ::std::net::AddrParseError) -> MyError {
        MyError()
    }
}

fn accept_addr(_addr: ::std::net::SocketAddr) {}

fn main() -> Result<(), MyError> {
    let addr = "127.0.0.1:23456".parse();
    let addr = addr.map_err(|e| e.into())?;
    Ok(accept_addr(addr))
}

不起作用。错误:

error[E0282]: type annotations needed
  --> src/main.rs:14:30
   |
14 |     let addr = addr.map_err(|e| e.into())?;
   |                              ^ consider giving this closure parameter a type

我无法按照上述错误消息中的建议解决此问题。如果我将代码更改为:

let addr = addr.map_err(|e: ::std::net::AddrParseError| e.into())?;

我收到另一个错误:

error[E0282]: type annotations needed
  --> src/main.rs:14:16
   |
14 |     let addr = addr.map_err(|e: ::std::net::AddrParseError| e.into())?;
   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for `_`

我的解决方案是使用 From 代替:

let addr = addr.map_err(|e| <MyError as From<_>>::from(e))?; // Worked!!

更好的是,我后来发现我什至不需要映射错误:

let addr = "127.0.0.1:23456".parse()?;
Ok(accept_addr(addr))

我知道类型推断绝非易事,但为什么上面的代码不能正确推断类型?

最佳答案

关于第二个错误:通过用另一个自定义错误 (MyError2) 替换解析获得的结果来稍微减少示例,会重现相同的问题 (|e: MyError2| e.into () 再次没有帮助):

#[derive(Debug)]
struct MyError();
struct MyError2();

impl From<MyError2> for MyError {
    fn from(_e: MyError2) -> MyError{
        MyError()
    }
}

fn main() -> Result<(),MyError> {
    let addr = Err(MyError2{});
    addr.map_err(|e| e.into())?;
    Ok(())
}
error[E0282]: type annotations needed
  --> src/main.rs:20:5
   |
20 |     addr.map_err(|e| e.into())?;
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for `_`

error: aborting due to previous error

用标准库中的宏定义 (try!) 替换 ? 显示:

macro_rules! try {
    ($e:expr) => (match $e {
        Ok(val) => val,
        Err(err) => return Err(::std::convert::From::from(err)),
    });
}

fn main() -> Result<(),MyError> {
    let addr = Err(MyError2{});
    let addr = try!(addr.map_err(|e| e.into()));
    Ok(addr)
}
error[E0282]: type annotations needed
  --> src/main.rs:14:13
   |
14 |         Err(err) => return Err(::std::convert::From::from(err)),
   |             ^^^ cannot infer type for `_`
...
20 |     let addr = try!(addr.map_err(|e| e.into()));
   |                -------------------------------- in this macro invocation

应用于宏定义中的 errFrom::from() 是导致推理失败的原因。将此行: Err(err) => return Err(::std::convert::From::from(err)), 替换为 Err(err) => return Err( err), 解决了问题 - 程序编译。

原因是,通过在 MyErrorMyError2 之间通过 From::from() 放置两个转换,此转换管道变得不明确。编译器无法确定中间类型。

示例 - 两个有效选项(请注意,From::from 是反射性实现的):

  • MyError2 -> MyError2 -> MyError

    编译:let addr = addr.map_err(|e| {let e2: MyError2 = e.into(); e2})?;

  • MyError2 -> MyError -> MyError

    编译:let addr = addr.map_err(|e| {let e2: MyError = e.into(); e2})?;

关于rust - 为什么使用 Into::into 解析字符串映射结果无法推断类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51155605/

相关文章:

c# - 使用解构元组赋值扩展方法进行类型推断

rust - 为什么打开克隆的 Rc 会引起 panic ?

multithreading - 在 Rust 中使用 `Result<T, Box<dyn Error>>` 技巧,但跨多个线程

rust - 为什么Rust会说我的变量未使用?

javascript - Typescript通用返回值推断问题

Scala 类型推断在明显的设置中崩溃?

types - 为什么Rust无法推断出Iterator::sum的结果类型?

rust - 如何通过一次检查将元组向量及其内容匹配?

rust - 无法使用 Cargo 构建 Rust 教程中的 hello world 示例

c# - "var"C# 中的类型推断