Reputation: 532
I'm stuck with the Rust concepts of borrowing and mutable:
#[derive(Debug)]
struct Rectangle {
height: u32,
width: u32,
}
fn mut_area(rect_mut: &mut Rectangle) -> u32 {
rect_mut.width /= 2;
rect_mut.height * rect_mut.width
}
fn mut_string(s: &mut String) -> &str {
s.push_str("!");
let len = s.len();
&s[0..len / 2]
}
fn main() {
let mut rect = Rectangle {
height: 50,
width: 40,
};
println!("original rect: {:?}", rect);
let a = mut_area(&mut rect);
println!("area of rect: {}", a);
println!("now rect: {:?}", rect);
let mut s = String::from("helloworld");
println!("original s: {}", s);
let half = mut_string(&mut s);
println!("half of the modified string: {}", half);
println!("modified s: {}", s);
}
When I tried to compile it, the compiler told me:
error[E0502]: cannot borrow `s` as immutable because it is also borrowed as mutable
--> <anon>:32:32
|
30 | let half = mut_string(&mut s);
| - mutable borrow occurs here
31 | println!("half of the modified string: {}", half);
32 | println!("modified s: {}", s);
| ^ immutable borrow occurs here
33 | }
| - mutable borrow ends here
I know there's a rule about mutable reference:
you can only have one mutable reference to a particular piece of data in a particular scope.
But why can rect
be borrowed but s
cannot be? And how do I achieve what I want here - to print the modified string after the function call?
Upvotes: 2
Views: 1617
Reputation: 22253
The reason why you can print a
after calling a function with a mutable reference to rect
is that it returns a u32
which is Copy
able - there is no need to restrict further uses of rect
because it is no longer borrowed after mut_area
is called.
Your mut_string
, on the other hand, returns a reference to its argument, so the mutable borrow remains in force as long as half
is in scope. That's why you may not borrow s
immutably for the purpose of println!()
.
In order to achieve what you are after I would mutate s
outside of the mut_string
function (a slightly different name would be a good idea now) so there is no mutable borrow in force - its argument can be borrowed immutably instead:
fn mut_string(s: &str) -> &str {
let len = s.len();
&s[0..len / 2]
}
fn main() {
let mut rect = Rectangle {
height: 50,
width: 40,
};
println!("original rect: {:?}", rect);
let a = mut_area(&mut rect); // rect's mutable borrow expires after this assignment
println!("area of rect: {}", a);
println!("now rect: {:?}", rect);
let mut s = String::from("helloworld");
println!("original s: {}", s);
s.push_str("!"); // s is mutated here
let half = mut_string(&s); // s is borrowed immutably
println!("half of the modified string: {}", half);
println!("modified s: {}", s); // another immutable borrow of s
}
Upvotes: 2