使用and_then组合器时,为什么我的错误类型没有自动更改?

时间:2017-02-19 17:06:03

标签: rust

我遇到了一些我不了解ResultFromand_then的内容。

我的impl Parser中有这个函数,当没有足够的字节时,它会给我一个字节片段或ParseError

fn consume_bytes(self: &mut Parser<'a>, len: usize) -> Result<&[u8], ParseError> {
    // ...
}

我正在尝试定义另一个函数:

fn read_utf8(self: &mut Parser<'a>, len: usize) -> Result<String, ParseError> {
    self.consume_bytes(len)
        .and_then(|bytes| String::from_utf8(bytes.to_vec()))
}

无法编译:

error[E0308]: mismatched types
   --> src/parser.rs:147:31
    |
147 |             .and_then(|bytes| String::from_utf8(bytes.to_vec()))
    |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `parser::ParseError`, found struct `std::string::FromUtf8Error`
    |
    = note: expected type `std::result::Result<_, parser::ParseError>`
               found type `std::result::Result<std::string::String, std::string::FromUtf8Error>`

因为我已经定义了From的实现,所以我希望转换能够自动执行,因为通过使用try!宏,转换是自动的(根据我的理解):< / p>

impl From<FromUtf8Error> for ParseError {
    fn from(err: FromUtf8Error) -> ParseError {
        ParseError::InvalidConstantPoolEntry(err)
    }
}

这是另一次尝试失败并出现相同的错误消息:

fn read_utf8(self: &mut Parser<'a>, len: usize) -> Result<String, ParseError> {
    self.consume_bytes(len)
        .and_then(|bytes| String::from_utf8(bytes.to_vec()))
        .map_err(|e| From::from(e))
}

这个版本map_err 里面 and_then lambda,有效:

fn read_utf8(self: &mut Parser<'a>, len: usize) -> Result<String, ParseError> {
    self.consume_bytes(len)
        .and_then(|bytes| String::from_utf8(bytes.to_vec()).map_err(|e| From::from(e)))
}

为什么and_then没有按预期工作?

PS:更具惯用性:我试图在上面编写或使用?运算符/ try!宏的版本?

fn read_utf8(self: &mut Parser<'a>, len: usize) -> Result<String, ParseError> {
    let bytes = self.consume_bytes(len)?;
    Ok(String::from_utf8(bytes.to_vec())?)
}

1 个答案:

答案 0 :(得分:2)

  

我原本希望转换能够自动执行,因为使用try!宏可以自动转换(根据我的理解)。

但你并没有使用 try!宏!

fn read_utf8(self: &mut Parser<'a>, len: usize) -> Result<String, ParseError> {
    self.consume_bytes(len)
        .and_then(|bytes| String::from_utf8(bytes.to_vec()))
}

谢天谢地,你打电话的代码不会对你的代码产生任何影响。

查看Result::and_then的签名:

fn and_then<U, F>(self, op: F) -> Result<U, E> 
    where F: FnOnce(T) -> Result<U, E>

它需要一个闭包,返回Result,其中包含我们开始的相同的错误类型。这里没有自动转换错误类型。 可能是成功类型的一些转换,具体取决于闭包选择做什么。

这就是您在and_then中转换错误类型的版本有效的原因,因为您已将错误类型从FromUtf8Error转换为ParseError,从而使错误类型返回闭包与and_then期望的匹配。