代码之家  ›  专栏  ›  技术社区  ›  Earth Engine

为什么将使用into::解析字符串的结果映射到无法推断类型?

  •  2
  • Earth Engine  · 技术社区  · 6 年前

    以下( 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))
    

    我知道类型推断从来都不容易,但是为什么上面的代码不能正确地推断类型呢?

    2 回复  |  直到 6 年前
        1
  •  3
  •   Calculator    6 年前

    关于第二个错误:通过用另一个自定义错误替换从解析中获得的结果来稍微减少示例( 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
    

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

    原因是通过放置两个转换 发件人::发件人() 之间 MyError 髓鞘2 此转换管道变得不明确。编译器无法确定中间类型。

    示例-两个有效选项(注意 From::from 实施反射式):

    • 髓鞘2 -> 髓鞘2 -> 迈罗

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

    • 髓鞘2 -> 迈罗 -> 迈罗

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

        2
  •  2
  •   Shepmaster Tim Diekmann    6 年前

    Parsing a string can return any number of types 以下内容:

    pub fn parse<F>(&self) -> Result<F, <F as FromStr>::Err>
    where
        F: FromStr, 
    

    你的代码没有任何关于 什么 在开始处理之前,应该从字符串中解析出来,所以编译器不知道 parse 选择:

    let addr = "127.0.0.1:23456".parse();
    let addr = addr.map_err(|e| e.into())?;
    

    然后尝试将未知类型转换为 MyError ,因此出错。

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

    了解 错误 类型不够,因为多个类型可以实现 FromStr 具有相同的错误类型:

    pub trait FromStr {
        type Err;
        fn from_str(s: &str) -> Result<Self, Self::Err>;
    }
    

    这意味着编译器仍然不知道该解析为什么。

    一般来说,编译器不会进行多次推理,因为搜索空间可能会成倍增大。在其他情况下,电流 临时的 特质系统没有足够的知识/努力使某些类型的推理起作用。有可能 switching to chalk 将使类型系统在数学上更加严格。


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

    这可以写得更简单:

    let addr = addr.map_err(|e| MyError::from(e))?;
    

    我甚至不需要映射错误

    是的,因为 ? 为你做的。