0

I am new to rust, and am missing the if let and guard let notation in Swift.

I have the following code block:

fn some_function() -> Option<String> {
  let client = reqwest::Client::new();

  // res is normally a response type. I've mapped it to an Option type to drop the error
  let res = client
    .post(&complete_path)
    .basic_auth(self.username.clone(), Some(self.password.clone()))
      .send()
      .ok();

  // Verify status code and exist if res = None, or status !== 200
  let mut response = match res {
    Some(res) => match res.status() {
      StatusCode::OK => res,
      _ => return None
    },
    _ => return None
  };

  // Attempt to read the body contents
  let token = match response.text() {
    Ok(data) => Some(data),
    Err(_e) => None
  };

  token
}

In swift I would have written something like:

guard let response = response,
  response.status == 200
  let text = response.text() else {
  return None
}
return text

Am I missing some shorthand notation?

I'm trying to make use of the ability to return from anywhere with return to short circuit some of the execution, but it's still much more verbose than I am familiar with.


EDIT:

I can collapse some of the rust with the match + clause syntax as below:

let mut response = match res {
  Some(res) if res.status() == StatusCode::OK => res,
  _ => return None
}

That is much better than the original.

If let also works, but the problem with if let here is that I'm looking at the failure path here. I do not want to nest in on the happy path.

Nathan Tornquist
  • 6,468
  • 10
  • 47
  • 72
  • 1
    [`if let`](https://doc.rust-lang.org/stable/rust-by-example/flow_control/if_let.html) and [`?`](https://doc.rust-lang.org/edition-guide/rust-2018/error-handling-and-panics/the-question-mark-operator-for-easier-error-handling.html) ...? – joel Jul 15 '20 at 21:45
  • ~I don't want to return a result.~ I was unaware that ? worked for Result and Option. Thank you – Nathan Tornquist Jul 15 '20 at 21:48

1 Answers1

1

There are proposals to make more flexible equivalents (guards, if let … && …), but in this case since you’re exiting by returning None you can make use of the question mark operator:

fn some_function() -> Option<String> {
  let client = reqwest::Client::new();

  let res = client
    .post(&complete_path)
    .basic_auth(self.username.clone(), Some(self.password.clone()))
      .send()
      .ok()?;

  if res.status() != StatusCode::OK {
    return None;
  }

  response.text().ok()
}

Consider also returning a Result<String, …> (Box<dyn Error>?) instead, which might be a cleaner API and which would let you skip the .ok().

Ry-
  • 218,210
  • 55
  • 464
  • 476