1

I'm only a few days into my Rust journey and going over my now functionally completed first project, working on exercising unwrap()s from my code.

The first two instances I've tried, I've completely failed and I cannot work out why. I have this line in my code:

let json = str::from_utf8(&buf).unwrap();

from_utf8 returns Result<&str, Utf8Error>, but trying:

let json = str::from_utf8(&buf)?;

Has a compiler error of "This function should return Result or Option to accept ?", but it does return Result. I can only assume that the pointer & is having an effect here?

I've refactored this now to:

match str::from_utf8(&buf) {
    Ok(json) => {
        let msg: MyMessage = serde_json::from_str(json).unwrap();
        self.tx.try_send((msg, src)).expect("Could not send data");
    }
    Err(e) => {}
};

I still need to work out what to do in the Err but I've gotten rid of the unwrap() call. However, there's another.

serde_json::from_str(json).unwrap();

This returns Result<T>, so:

serde_json::from_str(json)?;

This is also complaining about the fact it should return Result when it already does.

At this point, it's safe to assuming I'm really confused and I don't understand half as much as a thought I did.

Countless blogs just say use ?, yet, in every instances I think it should work and the return types appear suitable, the compiler says no.

Would the From trait work here? Is it common to have to write traits like this?

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Jammer
  • 9,969
  • 11
  • 68
  • 115

2 Answers2

2

from_utf8 returns Result<&str, Utf8Error>, but trying:

let json = str::from_utf8(&buf)?;

Has a compiler error of This function should return Result or Option to accept ?. But it does return Result.

This function here refers to the outer function. That is, the function you are writing, not from_utf8.

? will return an error from your function if there was one, thus your function needs the right return type to be able to return an error.

Because from_utf8 is not the source of the issue, you'd get the same error like this too:

let r = Err(...);
let json = r?;
Acorn
  • 24,970
  • 5
  • 40
  • 69
  • So obvious now you have pointed it out. But what if the outer method doesn't return anything intentionally? I'm going to update my question as this is really relevant to the solution. Thank you. – Jammer Jul 15 '22 at 08:34
  • Actually I don't think I need too. `?` isn't going to work in my instance and I need to implement them all as `match` since this is a loop executing on a thread, it's kind of a `fire and forget` thread entry point with no return value. – Jammer Jul 15 '22 at 08:37
  • @Jammer `?` isn't a shorthand for `unwrap`, which is what you seem to want. So it doesn't make sense to use it for that purpose. – Acorn Jul 15 '22 at 11:52
  • Yeah, I've actually figured it all out now. Handling all the errors and ok;s. Thanks for your help. – Jammer Jul 15 '22 at 11:54
  • @Jammer It is also unlikely you need `match`. At least you don't need it for the examples you showed (unwrapping and ignoring errors). – Acorn Jul 15 '22 at 11:58
  • Ahhh, OK. More food for thought!! – Jammer Jul 15 '22 at 12:01
2

The ? operator is roughly equivalent to a match with an early return for the error case, so in your example

fn foo() {
    let json = str::from_utf8(&buf)?;
    // ...
}

is roughly equivalent to

fn foo() {
    let json = match str::from_utf8(&buf) {
        Ok(j) => j,
        Err(e) => return Err(e.into()),
    }
    // ...
}

This should make it clear where the error is coming from. You are trying to return a Result from a function that doesn't return anything.

Holloway
  • 6,412
  • 1
  • 26
  • 33