Complete these tasks to reinforce what you learned in this module.
Write a function first_char(s: &str) -> Option<char> that returns the first character of s if non-empty. In main, create a String, call first_char(&s), and print the result. Use a non-empty string so you get Some(c).
&str parameter so you don’t take ownership. There is a method on str/chars that gives you the first character as an Option.// Task 1: Immutable borrow, first_char. See tasks/TASKS.md.
fn main() {
todo!("Implement first_char and call it");
}
The starter code in src/bin/task_02.rs does not compile. It tries to hold two mutable references to the same String at the same time. Your job is to uncomment it and fix it so it compiles and prints the expected output. Do not change what it prints.
The broken code:
``rust
fn append(s: &mut String, suffix: &str) {
s.push_str(suffix);
}
fn main() {
let mut s = String::from("foo");
let r1 = &mut s;
let r2 = &mut s; // second mutable borrow while r1 is still alive
append(r1, "bar");
append(r2, "baz");
println!("s = {}", s);
}
Compiling it produces:
error[E0499]: cannot borrow s as mutable more than once at a time
--> src/bin/task_02.rs:NN:14
|
LL | let r1 = &mut s;
| ------ first mutable borrow occurs here
LL | let r2 = &mut s; // second mutable borrow while r1 is still alive
| ^^^^^^ second mutable borrow occurs here
LL |
LL | append(r1, "bar");
| -- first borrow later used here
A &mut` is an exclusive borrow: only one can be live at a time. This is the rule that, in C#, you would only ever discover at runtime (or not at all) — Rust catches the aliasing-plus-mutation bug at compile time.
&mut s borrow ends as soon as append returns, so take a *fresh* &mut s for each call (append(&mut s, "bar"); append(&mut s, "baz");). The single mutable borrow never overlaps with another.// Task 2: Fix the borrow-checker error (make it compile). See tasks/TASKS.md.
//
// The code below does NOT compile. It tries to hold TWO mutable references to
// the same `String` at once. Rust forbids that: a `&mut` is an *exclusive*
// borrow, so only one may be live at a time. Compiling it once gives:
//
// error[E0499]: cannot borrow `s` as mutable more than once at a time
// --> src/bin/task_02.rs:NN:14
// |
// LL | let r1 = &mut s;
// | ------ first mutable borrow occurs here
// LL | let r2 = &mut s; // second mutable borrow while r1 is still alive
// | ^^^^^^ second mutable borrow occurs here
// LL |
// LL | append(r1, "bar");
// | -- first borrow later used here
//
// YOUR JOB: delete the `todo!()` below, uncomment the code, and fix it so the
// program compiles and prints exactly:
//
// s = foobarbaz
//
// HINT: You do not need two stored references. A `&mut s` borrow ends as soon
// as `append` returns, so you can take a *fresh* `&mut s` for each call.
//
// fn append(s: &mut String, suffix: &str) {
// s.push_str(suffix);
// }
//
// fn main() {
// let mut s = String::from("foo");
//
// let r1 = &mut s;
// let r2 = &mut s; // second mutable borrow while r1 is still alive
//
// append(r1, "bar");
// append(r2, "baz");
//
// println!("s = {}", s);
// }
fn main() {
todo!("Uncomment the code above and fix the double mutable borrow (E0499)");
}