Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rust chaining Results (Combinators)

I've been following a Rust tutorial where two versions of a function are purported to generate the same results:

Version 1:

pub fn get_transactions(fname:&str) -> Result<Vec<Transaction>,String> {
    let s = match std::fs::read_to_string(fname){
        Ok(v)=>v,
        Err(e)=> return Err(e.to_string()),
    };
    let t:Vec<Transaction> = match serde_json::from_str(&s) {
        Ok(v)=>v,
        Err(e)=> return Err(e.to_string()),
    };
    Ok(t)
}

Version 2:

fn get_transactions_b(fname:&str) -> Result<Vec<Transaction>,String> {
    std::fs::read_to_string(fname)
    .map_err(|e| e.to_string())
    .and_then(|ld| serde_json::from_str(&ld) )
    .map_err(|e| e.to_string())
}

However, I get the following message for version 2:

mismatched types

expected struct std::string::String, found struct serde_json::error::Error

note: expected enum std::result::Result<_, std::string::String> found enum std::result::Result<_, serde_json::error::Error>

help: try using a variant of the expected enum: _::_serde::export::Ok(serde_json::from_str(&ld)),


which I been unable to make head or tail out of:

  • Hovering over ld closure argument |ld| in VS Code it says it's of type std::string::String

  • Hovering over the ld in the from_str(&ld) I get the message.

  • Now I understand a Result is comprised of an Ok and an Err, but I thought the combinator chaining would have worked.

  • The compiler suggested fix doesn't work either.

    • (or make sense): What is the _::_ all about?
    • Why would the Ok not be inside the from_str?
  • What would you have to do to make version 2 work?

Here's the Result with the methods for combinators in the Rust docs.


Cargo.toml

[dependencies]
serde = "1.0.115"
serde_derive = "1.0.115"
serde_json = "1.0.57"

  • cargo 1.45.1
  • rustc 1.45.2
like image 988
JGFMK Avatar asked Aug 11 '20 13:08

JGFMK


People also ask

What is a combinator in rust?

A combinator is a function which builds program fragments from program fragments; in a sense the programmer using combinators constructs much of the desired program automatically, rather that writing every detail by hand. The exact definition of “combinators” in Rust ecosystem is bit unclear. Convert type T by applying a closure.

What is the use of map() in rust?

Rust also provides map () as an iterator adaptor to apply a closure on each element of an iterator to transform it into another iterator. However in here we are talking about the functionality of map () with Option and Result types.

What is a combinator?

One meaning of “combinator” is a more informal sense referring to the combinator pattern, a style of organizing libraries centered around the idea of combining things.


Video Answer


1 Answers

The problem comes from the and_then call.

You are not allowed to change the error type when calling and_then. So your function there should return a Result<Vec<Transaction>, String>. However, the error type returned by serde_json::from_str is a serde_json::error::Error.

You can fix it like this:

std::fs::read_to_string(fname)
    .map_err(|e| e.to_string())
    .and_then(|ld| serde_json::from_str(&ld).map_err(|e| e.to_string()))

Notice the call to map_err is now inside the function passed to and_then.

like image 68
Sunreef Avatar answered Oct 22 '22 14:10

Sunreef