Skip to content
tezvyn:

Go if err != nil versus Rust's ? operator

MediumHow cards are made

Summary

judgment on error-handling ergonomics.

Key points

Go's explicit checks are verbose but make every error site visible; Rust's ? propagates concisely while still forcing the error into the type, reducing boilerplate.

What's really being asked

It probes whether you understand the ergonomics and safety trade-offs of explicit error checks versus concise propagation, without mischaracterizing either mechanism.

The full answer

Go's idiom is to assign (val, err) and immediately write if err != nil { return ..., err }. This is explicit and uniform: every place an error can occur is visible in the code, which aids auditing, but it is verbose and can dominate a function with boilerplate. Crucially, the compiler does not force the check; you can ignore err via the blank identifier, so unhandled errors are possible and rely on linters and review. Rust's ? operator, written after a Result-returning expression, evaluates to the inner value on Ok and on Err returns early from the enclosing function after applying a From conversion to the error type. This keeps the happy path readable and removes boilerplate, while the type system still requires you to handle the Result; to deliberately ignore one you must write unwrap, expect, or let _ =, making the choice explicit and greppable.

Verbosity and readability

Go trades concision for visibility and simplicity. Rust trades a small amount of magic in ? for concision plus stronger guarantees. Neither uses exceptions; ? is ordinary early return, not unwinding.

The mistakes people make

Calling ? a hidden exception or saying it can panic (it returns, it does not panic). Saying Go forces you to handle errors. Claiming Rust hides where errors occur; ? marks each propagation point with a visible symbol.

What usually comes next

How does ? interact with the From trait and error conversion? What return types allow ? in main? How do anyhow and thiserror change the ergonomics?

A concrete example

Reading a file then parsing it: in Go you write two separate if err != nil blocks between the open, read, and parse calls. In Rust the same logic is let data = std::fs::read_to_string(path)?; let n: i32 = data.trim().parse()?; where each ? both propagates the error and converts it, and the function still cannot pretend the errors do not exist.

Interview question

What is true about Rust's ? operator compared with Go's explicit if err != nil checks?

  • a.? concisely propagates errors as an early return while the type still forces handling; Go's check can be silently skippedCorrect
  • b.? hides the location of error propagation entirely
  • c.Go's compiler forces every error to be handled, unlike Rust
  • d.? throws an exception that unwinds the stack
Why?

? is sugar for an early return on Err (with From conversion), keeping handling type-enforced, while Go lets you discard err with the blank identifier. ? is not an exception and marks each propagation point visibly.

Just read this? Test yourself on what you have been reading.

Put your scrolling time to good use

Learn one idea, try a quiz and save useful cards for revision. Tezvyn makes it easy to learn and stay current in your tech field, a few minutes at a time.

The iPhone app is on the way

We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.

Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.

Get it on Google PlayiPhone app coming soon

We are hiring for this. Open roles that interview on go — each one lists the topics its interview covers.

See open roles