Return type of read_to_string

Total newbie to Rust (obviously).

The read_to_string return type is documented thus:

pub fn read_to_string<P: AsRef<Path>>(path: P) -> Result<String>

Yet, when I return that from a calling function thus:

  fn read_config_file() -> Result<String> {
    fs::read_to_string("/Users/acohen/.sinkerrc.json");
  }
}

I get:

wrong number of type arguments: expected 2, found 1
expected 2 type argumentsrustc(E0107)
lib.rs(21, 37): expected 2 type arguments

...which I assume means I need to return a Result with an Error as well. This makes sense as an io operation likely could result in an error.

If I return Result<String, Error> and import Error like this:

use std::error::Error;

, I get:

the size for values of type `(dyn std::error::Error + 'static)` cannot be known at compilation time
doesn't have a size known at compile-time
help: the trait `std::marker::Sized` is not implemented for `(dyn std::error::Error + 'static)`rustc(E0277)

If that's the case, what's up with the docs on read_to_string? I would assume the docs would be clear about its return type and thus I could use the same return type in the calling function above.

Clearly I'm missing something and glad in advance to be taught...

Please post the full error message.

Edited

In the future, please put error messages in code blocks. That makes them much easier to read.

The problem here is that std::error::Error is a trait, and traits are not types, and their values cannot exist on their own. To exist as a value, a trait must be behind a reference or smart pointer (often a Box).

Anyway, you are probably looking for std::io::Error here, which is not a trait, but an actual type.

Yes, but if you check what is this Result, you'll see that it's not the ordinary Result, but std::io::Result. Just return it explicitly, and all should be good.

2 Likes

Got it, but why do I need to explicitly return it? Doesn't rust return the last expression?

I mean, explicitly state in your function signature, that it is std::io::Result.

Yes - this feature will allow you to write:

fn read_config_file() -> Result<String> {
    fs::read_to_string("/Users/acohen/.sinkerrc.json")
    // Instead of 
    // return fs::read_to_string("/Users/acohen/.sinkerrc.json");
}

It doesn't affect how the signature of the function looks at all though.

Rust doesn't infer the signatures of functions by design. You should write types explicitly on function definitions.

1 Like

Rust has std::result::Result and std::io::Result, which unfortunately are two different types.

Same with std::error::Error interface (trait) and std::io::Error type.

In this case I think rustdoc is just not presenting it clearly enough. It should be showing io::Result IMHO.

The std::error::Error isn't a thing that can be returned, because it's only a trait, an interface that describes how to implement actual types, but by itself it has no data.
Because returning a trait wouldn't make sense, Rust interprets your trait syntax as dyn Error, which unfortunately also doesn't make sense here either. You'd need either Box<dyn error::Error> or io::Error>.

2 Likes

Got it. Thanks. Yeah, the docs were super confusing to me.

So does std::io::Result is just a shortcut so you don't have to write out the Error type?

Precisely. This is a common Rust pattern used in lots of crates.

1 Like