Rust āā A language empowering everyone to build reliable and efficient software.
Lec03: Error Handling
Ownership
Example One:
|
|
The problem is in the first f(s)
, main
has give s
ās ownership to f
, and f
doesnāt give it back. So main
lose s
ās ownership in the second f(s)
. By the way, after the first f(s)
ends, s
will be free.
šExceptionļ¼
|
|
It works fine because u32
implements a ācopy traitā that changes what happens when it is assigned to variables or passed as a parameter.
Good news, only primitive types + a handful of others use copy semantics, and you just need to remember those.
Example Two:
|
|
It works fine, because s
s1
s2
are all immutable.
Remember, you can have as many read-only pointers to something as you want, as long as no one can change what is being pointed to.
šĀ Counter Example One:
|
|
This fails to compile becauseĀ s
Ā is immutable, and on the next line, we try to borrow aĀ mutableĀ reference toĀ s
. If this were allowed, we could modify the string usingĀ s1
, even though it was supposed to be immutable.
šĀ Counter Example Two:
|
|
This fails again, but for a different reason.
- We first declareĀ
s
Ā as mutable. š - We borrow a mutable reference toĀ
s
. š - We try to borrow an immutable reference toĀ
s
. However, there already exists a mutable reference toĀs
. Rust doesnāt allow multiple references to exist when a mutable reference has been borrowed. Otherwise, the mutable reference could be used to change (potentially reallocate) memory when code using the other references least expect it.
šĀ Counter Example Three:
|
|
- We first declareĀ
s
Ā as mutable. š - We borrow a mutable reference toĀ
s
. š - We try to useĀ
s
. However, the value has been āborrowed outā toĀs1
Ā and hasnāt been āreturnedā yet. As such, we canāt useĀs1
.
Example Three:
|
|
It works fine.
šĀ Thinking
āOne thing thatās confusing is why sometimes I need to &var and other times I can just use var: for example, set.contains(&var), but set.insert(var) ā why?"
Answer:
When inserting an item into a set, we want to transfer ownership of that item into the set; that way, the item will exist as long as the set exists. (It would be bad if you added a string to the set, and then someone freed the string while it was still a member of the set.) However, when trying to see if the set contains an item, we want to retain ownership, so we only pass a reference.
Error Handling about null pointer
Introduce Option<T> in Rust
Null pointer is dangerous in C/C++. To solve this problem, we might want some way to indicate to the compiler when a valueĀ mightĀ beĀ NULL
, so that the compiler can then ensure code using those values is equipped to handleĀ NULL
.
Rust does this with theĀ Option
Ā type. A value of typeĀ Option<T>
Ā can either beĀ None
Ā orĀ Some(value of type T)
.
Definition of Option<T>:
|
|
Example:
|
|
Handling errors
Introduce Result<T, E> in Rust
- C has an absolutely garbage system for handling errors.
- C++ and many other languages use exceptions to manage error conditions. It works well, but also has many disadvantages
- failure modes are hard to spot
Rust takes a different, two-pronged approach to error handling
- unrecoverable error, use
panic!
|
|
Panics terminate the program immediately and cannot be caught.
(Side note: itās technically possible to catch and recover from panics, but doing so really defeats the philosophy of error handling in Rust, so itās not advised.)
- recoverable error
You should return aĀ Result
. If you returnĀ Result<T, E>
, you can either returnĀ Ok(value of type T)
Ā orĀ Err(value of type E)
|
|
Or you could use unwrap
instead
|
|
If theĀ Result
Ā wasĀ Ok
,Ā unwrap()
Ā returns the success value; otherwise, it causes a panic.Ā
expect()
Ā does the same thing, but prints the supplied error message when it panics
Written by Jiacheng Hu, at Zhejiang University, Hangzhou, China.