Complete these tasks to reinforce what you learned in this module.
Create a String::from("moved"), assign it to a second variable (so it moves), then print the second variable only.
String with String::from(...), then assign it to another variable. Remember: after the assignment, only the new owner can use the value. Print from the variable that owns the string.// Task 1: Move and use. See tasks/TASKS.md.
fn main() {
todo!("Create String, move it, print the new owner");
}
The program below does not compile. Coming from C#, you would expect let copy = original; to hand you a second handle to the same string and leave original usable. In Rust, String is not Copy, so that assignment moves ownership out of original, and the later println! borrows a value that no longer owns anything. Open src/bin/task_02.rs, uncomment the broken block, and fix the single line that moves the value so the program compiles and prints both strings.
The broken code:
``rust
fn main() {
let original = String::from("hello");
let copy = original; // moves ownership out of original
println!("original = {}", original);
println!("copy = {}", copy);
}
Compiling it as-is fails with the real borrow-checker error:
error[E0382]: borrow of moved value: original
--> src/bin/task_02.rs:NN:NN
|
| let original = String::from("hello");
| -------- move occurs because original has type String,
| which does not implement the Copy trait
| let copy = original; // moves ownership out of original
| -------- value moved here
| println!("original = {}", original);
| ^^^^^^^^ value borrowed here after move
|
= help: consider cloning the value if the performance cost is acceptable
String for you (that would hide a heap allocation), but it gives you a method to ask for an explicit deep copy. Call it on original when you create copy. In C#: string copy = original; just copies the reference and both point at the same object; the explicit deep copy here is closer to allocating a brand-new string.// Task 2: Make it compile (fix the use-after-move). See tasks/TASKS.md.
//
// The code below is BROKEN. Coming from C#, you would expect `let copy = original;`
// to give you a second handle to the same string and leave `original` usable.
// In Rust, `String` is not `Copy`, so that assignment MOVES ownership out of
// `original`, and the later `println!` tries to use a value that no longer owns
// anything. This is the single most important borrow-checker lesson for a
// GC-background developer.
//
// If you uncomment the block below as-is, `cargo build` fails with:
//
// error[E0382]: borrow of moved value: `original`
// --> src/bin/task_02.rs:NN:NN
// |
// | let original = String::from("hello");
// | -------- move occurs because `original` has type `String`,
// | which does not implement the `Copy` trait
// | let copy = original; // ownership moves out of `original` here
// | -------- value moved here
// | println!("original = {}", original);
// | ^^^^^^^^ value borrowed here after move
// |
// = help: consider cloning the value if the performance cost is acceptable
//
// YOUR JOB: uncomment the block and fix the one line that moves the value so the
// program compiles and prints BOTH lines (see Expected in tasks/TASKS.md):
//
// original = hello
// copy = hello
//
// HINT: You want two independently owned strings. A `String` won't copy itself
// implicitly (that would hide a heap allocation), but it gives you a method to
// ask for an explicit deep copy. Call it on `original` when you create `copy`.
fn main() {
// --- BROKEN: uncomment and fix the `let copy = original;` line ---
// let original = String::from("hello");
// let copy = original; // moves ownership out of `original`
//
// println!("original = {}", original);
// println!("copy = {}", copy);
todo!("Uncomment the block above and fix the move so both lines print");
}