I have encountered something that I don't understand about Result, From, and_then.
I have this function in my impl Parser that will give me either a slice of bytes or a ParseError when there are not enough bytes:
fn consume_bytes(self: &mut Parser<'a>, len: usize) -> Result<&[u8], ParseError> {
// ...
}
I'm trying to define another function:
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()))
}
This fails to compile:
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>`
Because I have defined an implementation of From, I was expecting the conversion to be performed automatically, since by using the try! macro the conversion is automatic (from what I've understood):
impl From<FromUtf8Error> for ParseError {
fn from(err: FromUtf8Error) -> ParseError {
ParseError::InvalidConstantPoolEntry(err)
}
}
This is another attempt that fails with the same error message:
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))
}
This version, where the map_err is inside the and_then lambda, works:
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)))
}
Why doesn't and_then work as I expected?
PS: What's more idiomatic: the version I'm trying to write above or using the ? operator/the try! macro?
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())?)
}
.map_err(From::from)self: &mut Parser<'a>is not idiomatic, that's normally&mut self.