What unwrap does¶
Level: 101 · for newcomers
One line: unwrap() hands you the value inside an Ok or a Some, and panics on an Err or a None. The compiler checks nothing about whether that will happen: it is a method that decides at run time.
fn main() {
let good: f32 = "1.5".parse().unwrap(); // 1.5
let row = vec![1.0_f32, -1.0, 1.0];
let last = row.get(2).unwrap(); // &1.0
println!("{good} {last}"); // 1.5 1
}
The method, in full¶
On a Result, unwrap is one match. This is its source in core as shipped with rustc 1.98.0, attributes trimmed:
#[track_caller]
pub fn unwrap(self) -> T
where
E: fmt::Debug,
{
match self {
Ok(t) => t,
Err(e) => unwrap_failed("called `Result::unwrap()` on an `Err` value", &e),
}
}
unwrap_failed is a one-line helper that runs panic!("{msg}: {error:?}"). Option::unwrap is the same match with Some(val) => val, and its None arm panics with a fixed sentence. Blocks 1 and 2 of the verified output show both messages:
called `Result::unwrap()` on an `Err` value: ParseFloatError { kind: Invalid }called `Option::unwrap()` on a `None` value
It checks nothing at compile time¶
Explanations sometimes say that unwrap tells the compiler the result will be fine. The compiler is not told anything. This builds with no warning and panics when it runs:
thread 'main' (29385617) panicked at unwrap_x.rs:3:31:
called `Result::unwrap()` on an `Err` value: ParseFloatError { kind: Invalid }
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Two details in that message. 3:31 is the unwrap() in your file, not a line inside the standard library: unwrap is marked #[track_caller] (in the source above), so the panic reports where it was called. And the error is printed with {:?}, the Debug form, not the Display sentence invalid float literal (block 4). What a panic costs explains the rest: the exit status 101, and what is unwound.
In a test, the same panic makes the test fail, which is why unwrap in test code is ordinary. A first test, step by step shows a test failing exactly this way.
The error type must implement Debug¶
Because the message prints the error with {:?}, Result::unwrap only exists when E: Debug:
error[E0277]: `BadRow` doesn't implement `Debug`
--> no_debug.rs:8:26
|
8 | let row = read_row().unwrap();
| ^^^^^^ the trait `Debug` is not implemented for `BadRow`
|
help: consider annotating `BadRow` with `#[derive(Debug)]`
|
1 + #[derive(Debug)]
2 | struct BadRow;
|
The methods beside it¶
Block 3 sends the same Err through each:
| Method | On Ok(v) / Some(v) |
On Err / None |
|---|---|---|
unwrap() |
v |
panics with the error's Debug |
expect("…") |
v |
panics with your sentence, then the error |
unwrap_or(x) |
v |
x |
unwrap_or_else(f) |
v |
f(), called only now |
unwrap_or_default() |
v |
the type's default: 0.0 for f32 |
? |
v |
returns the Err or None from the function |
.ok() |
Some(v) |
None |
When unwrap is the right call¶
- In tests and examples, where a panic is the failure report you want.
- When the value cannot be missing and you can say why, which is when
expectis better, because it writes the reason down. - Not on input: text from a user, a file or the network can always be wrong, and a crash is rarely the right answer to that.
unwrapis a TODO you forgot to remove is about howunwraps arrive in real code and how to find them.
The verified output¶
Verified output of what_unwrap_does.rs — regenerated by tools/run_examples.py, never hand-typed.
1. On a Result
"1.5".parse::<f32>().unwrap() returned 1.5
"x".parse::<f32>().unwrap() panicked: called `Result::unwrap()` on an `Err` value: ParseFloatError { kind: Invalid }
2. On an Option
row.get(2).unwrap() returned 1.0
row.get(9).unwrap() panicked: called `Option::unwrap()` on a `None` value
3. The same Err through the methods beside unwrap
.expect("a CSV field") panicked: a CSV field: ParseFloatError { kind: Invalid }
.unwrap_or(0.0) returned 0.0
.unwrap_or_default() returned 0.0
.ok() returned None
4. The message uses the error's Debug form, not its Display form
Debug: ParseFloatError { kind: Invalid }
Display: invalid float literal
If you are coming from another language¶
Python. unwrap is what Python does by default: float("x") raises, and the program stops unless someone catches it. Rust inverts the default. The failure is a value you must deal with, and unwrap is the explicit request for Python's behaviour. The Option side has no direct equivalent: d["k"] raising KeyError is unwrap on a lookup, and d.get("k") is the Option itself.
ABAP. Calling a method that raises an exception, with no TRY … CATCH around it, ends in a short dump, and that is the closest match to an unwrap that panics. The difference is what shows up in the code: in Rust the risky call carries a visible .unwrap(), so the places that can crash can be found with a search.
See also¶
OkandErr— the typeunwraptakes apartSomeandNone— theOptionsideexpect—unwrapwith the reason written down- What a panic costs — what happens after the panic message
unwrapis a TODO you forgot to remove — why so manyunwraps survive, and the lint that finds them- Shadowing and
unwrap—let x = x.unwrap();, and what it does and does not change Result::unwrap↗ ·Option::unwrap↗
Po polsku¶
unwrap() wyjmuje wartość z Ok albo Some, a na Err albo None wywołuje panikę. To zwykła metoda — w bibliotece standardowej to jeden match — i decyduje w czasie działania programu. Kompilator niczego nie sprawdza: "x".parse::<f32>().unwrap() kompiluje się bez ostrzeżenia i kończy program z kodem 101. Zdanie, że unwrap „mówi kompilatorowi, że wszystko się uda”, jest więc nieprawdziwe.
Komunikat paniki ma dwie cechy warte zapamiętania. Wskazuje linię z .unwrap() w twoim pliku, a nie w bibliotece standardowej, bo metoda ma atrybut #[track_caller]. I wypisuje błąd w postaci Debug (ParseFloatError { kind: Invalid }), a nie Display (invalid float literal) — dlatego Result::unwrap istnieje tylko wtedy, gdy typ błędu implementuje Debug (inaczej E0277).
Obok unwrap stoi cała rodzina: expect (panika z własnym zdaniem), unwrap_or, unwrap_or_else, unwrap_or_default (wartość zastępcza bez paniki), ? (przekazanie błędu wyżej) i ok() (zamiana na Option). unwrap jest na miejscu w testach i przykładach, gdzie panika jest właściwym raportem, oraz tam, gdzie wartość naprawdę nie może być pusta — choć wtedy lepsze jest expect, które zapisuje powód. Na danych wejściowych od użytkownika, z pliku czy z sieci zwykle nie jest.
Szukaj po polsku: panika w Ruscie · rust unwrap · rust called Result::unwrap() on an Err value · rust called Option::unwrap() on a None value · rust unwrap vs expect · rust track_caller