以下(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))
我知道类型推断从来都不容易,但是上面的代码为什么不能正确地推断类型?
答案 0 :(得分:3)
关于第二个错误:通过将解析后的结果替换为另一个自定义错误(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),
解决了该问题-程序得以编译。
原因是,通过在From::from()
和MyError
之间通过MyError2
进行两次转换,此转换管道变得模棱两可。编译器无法确定中间类型。
示例-两个有效选项(注意From::from
是自反实现的):
MyError2
-> MyError2
-> MyError
编译:{{1}}
let addr = addr.map_err(|e| {let e2: MyError2 = e.into(); e2})?;
-> MyError2
-> MyError
编译:{{1}}
答案 1 :(得分:2)
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())?;
仅知道 error 类型是不够的,因为多种类型可以实现具有相同错误类型的FromStr
:
pub trait FromStr {
type Err;
fn from_str(s: &str) -> Result<Self, Self::Err>;
}
这意味着编译器仍然不知道解析为什么。
通常,编译器不会进行多次推理,因为搜索空间可能成倍增大。在其他情况下,当前的 ad hoc 特征系统不够了解/很难尝试使某些类型的推理工作。 switching to chalk可能会使类型系统在数学上更加严格。
let addr = addr.map_err(|e| <MyError as From<_>>::from(e))?;
这可以写得更简单:
let addr = addr.map_err(|e| MyError::from(e))?;
我什至不需要映射错误
是的,因为?
为您做到了。