Hacker News new | past | comments | ask | show | jobs | submit login

Not really. In Go you can `val, _ := func()` and use the value even if there is an error. AFAIK there is no equivalent in Rust (for Option) outside of unsafe shenaniganry. You can choose to panic / return err / etc, but you can't choose to use the value regardless of the presence of an error.



Yep. I'm pretty sure that even with unsafe shenanigans, you can't access the value without being very explicit about it. You'd need something like:

    let value = unsafe {
        match result {
            Ok(value) => value,
            _ => hint::unreachable_unchecked()
        }
    };
At this point, the fact that you've skipped an error check should be abundantly clear to anyone reading your code.


You can return tuples from Rust fns just like you would in Go, if that's your thing - no unsafe necessary:

  fn foo() -> (usize, Result<(),()>) { (0, Ok(())) }
  let (a, err) = foo(); err?; // propigate error
  let (b, _) = foo(); // discard error
Or more typically, you might use one of the many fn s such as unwrap_or, unwrap_or_else, unwrap_or_default, etc. - to provide your own appropriate default value. I usually find that useful default values are often caller specific anyways (and doesn't require remembering which fns return which default values on error):

  fn foo() -> Result<usize> { Ok(1) }
  fn bar() -> Option<usize> { None }
  let val = foo().unwrap_or(3); // val == 1
  let val = bar().unwrap_or(4); // val == 4
Alternatively you can use out parameters, which occasionally crops up in Rust's own stdlib:

  let mut line = String::new();
  let _ = buf_read.read_line(&mut line);
  // ...use line, even if there was an error...
Also, the "error" type might contain values itself, although you're certainly not ignoring the error if you use it:

  // https://doc.rust-lang.org/std/ffi/struct.OsString.html#method.into_string
  match os_string.into_string() {
      Ok(string) => println!("Valid UTF8 string: {}", string),
      Err(os_string) => println!("Invalid UTF8: {:?}", os_string),
  }


Sure, it's always possible to design a system that avoids the type system of a language. At worst case you can just resort to creating an un-typed lambda calculus and re-implementing your logic there.

Community habits and language frictions matter a lot. In Go, doing the equivalent of `Result` requires custom private types for every combination, with private fields and accessor methods that protect against misuse. And you still only gain runtime safety. And they can still make a zero-valued var and use it without "initialization" (unless you use private types, which are an even bigger pain for a variety of reasons). Any other approach makes it trivial to bypass - public fields can just be accessed, multiple returns can be ignored, etc. In Rust, the community and language make `Result` common, and then you gain compile-time safety in most cases, and warnings in all others (AFAIK, as Result is annotated as "must use", so you get a warning or a `_ =` as a visible marker that you're ignoring something).

---

tl;dr multiple returns of course bypass this, but in practice you won't see that in Rust unless it's intended to allow ignoring the error. Underscores on out-param funcs are a good point, but they're also fairly rare / serve as a visual warning of shenaniganry.


If you're not going to use the success value, you can ignore errors in Rust easily:

    let _ = something_returning_Result();
This does not even give a warning.


> This does not even give a warning.

Just to clarify: the "let _ = ..." construct is the explicit way of suppressing the warning in Rust. You acknowledge that there is indeed a return value but you choose to ignore it. Just calling the function without explicitly discarding the Result will give you a warning.




Consider applying for YC's W25 batch! Applications are open till Nov 12.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: