fn takes_ownership(some_string: String) { println!("'takes_ownership' received: {}", some_string); } // some_string goes out of scope and `drop` is called. fn borrows_immutably(s: &String) { println!("'borrows_immutably' received (immutable): {}", s); // s.push_str("world"); // This would cause a compile-time error } fn borrows_mutably(s: &mut String) { s.push_str(", world!"); println!("'borrows_mutably' received (mutable): {}", s); } fn main() { // Ownership let s1 = String::from("hello"); takes_ownership(s1); // s1's value moves into the function. // println!("{}", s1); // This would cause a compile-time error: value used after move let mut s2 = String::from("hello"); borrows_immutably(&s2); // s2 is immutably borrowed. println!("After immutable borrow: {}", s2); // s2 is still usable here. borrows_mutably(&mut s2); // s2 is mutably borrowed. println!("After mutable borrow: {}", s2); // s2 is still usable here, with its new value. // A variable can only have one mutable borrow OR any number of immutable borrows at a time. let mut s3 = String::from("Rust"); let r1 = &s3; // immutable borrow let r2 = &s3; // another immutable borrow println!("r1: {}, r2: {}", r1, r2); // let r3 = &mut s3; // This would cause a compile-time error as r1 and r2 are still active. }