I'm still new with Rust but I have doubts about how mutability works for fields in structs. Specifically how we can modify fields that originally were immutable. For example:
struct Point {
x: isize,
y: isize,
}
impl Point {
fn new(x: isize, y: isize) -> Self {
Self { x, y }
}
fn set_x(&mut self, new_x: isize) {
self.x = new_x;
}
}
struct Line {
p: Point,
q: Point,
}
impl Line {
fn new(p: Point, q: Point) -> Self {
Self { p, q }
}
fn set_x_in_p(&mut self, new_x: isize) {
self.p.set_x(new_x);
}
}
fn main() {
// Both x and y are immutable
let p = Point::new(0, 0);
let q = Point::new(1, 1);
// Line IS mutable
let mut line = Line::new(p, q);
// Modifying point p (originally immutable) with a new x
line.set_x_in_p(999);
}
Instead with references we cannot
let x = 3;
let y = &mut x; // does not work because x originally is immutable
So, how does it work? Thanks.
In your example, p and q are indeed immutable, but then you move them into a Line instance with the constructor, since they're passed by value and don't implement Copy to enable implicit copying. This means that the original bindings (p and q) are no longer valid (the compiler will prevent you from using them) and the values are instead accessible only via the mutable line binding, which allows mutating its members. Essentially, it's not the values that are mutable, but rather their bindings. For example, the following code can be used to re-bind a value to change its mutability:
let x = String::from("hello world"); // using String as an example of a non-Copy type
let mut x = x; // this shadows the previous binding with a mutable one of the same name
x.make_ascii_uppercase(); // we can now mutate the string
let x = x; // shadow the mutable binding with an immutable one
println!("Result: {}", x);
This example works because we have direct control over the value, and can move/bind it as desired. Introducing references would limit what could be done - for example, the following examples wouldn't work:
let x = String::from("hello world");
let x_ref = &x; // create an immutable reference to x
let mut x_mut = x; // error - we can't move x while it's borrowed
let x_mut_ref = &mut x; // error - we can't create a mutable reference while any other references exist
I'd recommend reading the ownership and moves page of Rust by example, which explains it pretty well.
When you are declaring x, you are specifying it as immutable with the let instead of let mut. When you then declare y and initialize it as &mut x you are attempting to borrow x. In Rust, the one thing you can never do is simultaneously have shared ownership AND mutability.
Check out what Niko Matsakis has to say about ownership.
Related
Since Iter's "all" fn takes type FnMut is it possible to update the element while checking for condition and short circuiting? Though I understand it is not supposed to, but what prevents it from updating the value?
fn main() {
let a = ["as", "zz"];
let mut iter = a.iter();
iter.all(|& (mut x)| {x = "cc"; true});
for z in a.iter(){
println!("{z}");
}
}
Above prints
as
zz
In above case why setting "x = cc" not work?
Or Alternatively why does Iter "all" method takes F of type FnMut and not Fn when it is not supposed to mutate but only validate for condition
x = "cc" does not change the value referred by x, instead it changes the reference itself (i.e. it makes it refer to another value), as evidenced by this example:
fn main() {
let a = ["as", "zz"];
let mut iter = a.iter();
iter.all(|&(mut x)| {
println!("before: {:?}", x as *const _);
x = "cc";
println!("after: {:?}", x as *const _);
true});
for z in a.iter(){
println!("{z}");
}
}
Playground
Note that this has nothing to do with the fact that the closure is FnMut, which only means that it may change any captured values as in:
fn main() {
let a = ["as", "zz"];
let mut count = 0;
let mut iter = a.iter();
iter.all(|&_x| {
count += 1; // This is possible because the closure is `FnMut`
true});
println!("Count: {count}");
for z in a.iter(){
println!("{z}");
}
}
Playground
Do not be mistaken! A function implementing FnMut means that it captures a receiving context mutably. It does not mean that its items may be modified from its original source.
let mut k = 0;
assert_eq!((10..15)..all(|x| {
k += 1;
x > k
}), true);
Given
let mut iter = a.iter();
we have an iterator the items of which are references to elements in vector a. And these references are immutable. In order to have an iterator which allows you to mutate the items in a vector, use iter_mut.
let iter = a.mut_iter();
iter.all(|x| { *x = "cc"; true});
for z in a.iter(){
println!("{z}");
}
This would still not require FnMut in particular, since it does not capture any context other than the items iterated on. The adaptor all (and many other iterator adaptors) were designed to constrain to FnMut so that the closures passed as their first parameter are allowed to keep and manipulate some external state for whichever logic they intend to do. Since the closure is called sequentially in the same thread, this is always memory safe.
See also:
What's the difference between placing "mut" before a variable name and after the ":"?
When does a closure implement Fn, FnMut and FnOnce?
Consider the following (contrived) way to increment x by 9.
fn main() {
let mut x = 0;
let mut f = || {
x += 4;
};
let _g = || {
f();
x += 5;
};
}
error[E0499]: cannot borrow `x` as mutable more than once at a time
--> x.rs:6:12
|
3 | let mut f = || {
| -- first mutable borrow occurs here
4 | x += 4;
| - first borrow occurs due to use of `x` in closure
5 | };
6 | let _g = || {
| ^^ second mutable borrow occurs here
7 | f();
| - first borrow later captured here by closure
8 | x += 5;
| - second borrow occurs due to use of `x` in closure
error: aborting due to previous error
For more information about this error, try `rustc --explain E0499`.
So, it does not work. How to make an algorithm like the above that would modify a variable in a closure and call another closure from it that also modifies the variable?
In traditional languages it's easy. What to do in Rust?
The accepted answer is the most idiomatic approach, but there is also an alternative that is useful in situations when the additional argument doesn't work, for example when you need to pass the closure to third-party code that will call it without arguments. In that case you can use a Cell, a form of interior mutability:
use std::cell::Cell;
fn main() {
let x = Cell::new(0);
let f = || {
x.set(x.get() + 4);
};
let g = || {
f();
x.set(x.get() + 5);
};
f();
g();
assert_eq!(x.get(), 13);
}
By design, closures have to enclose external objects that are used in it upon creation, in our case closures have to borrow the external x object. So as compiler explained to you, upon creation of the closure f it mutably borrows x, and you can't borrow it once again when you create closure g.
In order to compile it you can't enclose any external object that you want to change. Instead you can directly pass the objects as a closure's argument (arguably it's even more readable). This way you describe that a closure accepts some object of some type, but you don't yet use/pass any actual object. This object will be borrowed only when you call the closure.
fn main() {
let mut x = 0;
let f = |local_x: &mut i32| { // we don't enclose `x`, so no borrow yet
*local_x += 4;
};
let _g = |local_x: &mut i32| { // we don't enclose `x`, so no borrow yet
f(local_x);
*local_x += 5;
};
_g(&mut x); // finally we borrow `x`, and this borrow will later move to `f`,
// so no simultaneous borrowing.
println!("{}", x); // 9
}
To expand on Alex Larionov's answer: you should think of a closure as a callable structure, anything you capture is set as a field of the structure, then implicitly dereferenced inside the function body. The way those fields are used is also what determines whether the closure is Fn, FnMut or FnOnce, basically whether the method would take &self, &mut self or self if it were written longhand.
Here
fn main() {
let mut x = 0;
let mut f = || {
x += 4;
};
// ...
}
essentially translates to:
struct F<'a> { x: &'a mut u32 }
impl F<'_> {
fn call(&mut self) {
*self.x += 4
}
}
fn main() {
let mut x = 0;
let mut f = F { x: &mut x };
// ...
}
from this, you can see that as soon as f is created, x is mutably borrowed, with all that implies.
And with this partial desugaring, we can see essentially the same error: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=e129f19f25dc61de8a6f42cdca1f67b5
If we use the relevant unstable features on nightly we can get just a bit closer. That is pretty much what rustc does for us under the hood.
I'm going through the Rust book, and I'm on the chapter describing closures. I'm a bit confused about why the following example errors due to the closure taking ownership:
fn main() {
let x = vec![1, 2, 3];
let equal_to_x = move |z| z == x;
println!("can't use x here: {:?}", x);
let y = vec![1, 2, 3];
assert!(equal_to_x(y));
}
Namely, why does equal_to_x take ownership of x before it's even called? Shouldn't the compiler know that the closure hasn't been called (because it is owned by main) and thus x can still be owned by the outside scope of main?
Because a closure is essentially a struct with a function associated with it. I find it easier to think of closures like this:
struct MyClosure{
x: Vec<i32>
};
impl MyClosure {
pub fn execute(self, z: Vec<i32>) -> bool {
z == self.x
}
}
If thought of like this, your code is equivalent to
let equal_to_x = MyClosure {
x
};
so you can see why the move has happened.
Take this example:
fn main() {
let dato = std::sync::Arc::new(std::sync::Mutex::new(1u8));
for _ in 0..3 {
let value = dato.clone();
std::thread::spawn(move || {
let v = value.lock().unwrap();
*v += 1; // <- Error
});
}
std::thread::sleep(std::time::Duration::from_secs(1u64));
println!("{:?}", dato);
}
cannot borrow immutable local variable v as mutable
I know that changing to mut works:
std::thread::spawn(move || {
let mut v = value.lock().unwrap();
*v += 1;
});
but why does this work:
let value = dato.clone();
std::thread::spawn(move || {
*value.lock().unwrap() += 1;
});
playground
value.lock().unwrap() returns a value of type MutexGuard, which has a DerefMut implementation:
impl<'mutex, T: ?Sized> DerefMut for MutexGuard<'mutex, T> {
fn deref_mut(&mut self) -> &mut T { ... }
}
DerefMut::deref_mut(x) is equivalent to &mut *x; naturally, DerefMut is also used for assignments under the pointer, like in your case.
Therefore, for *v += 1 to work, v should be a mut variable - otherwise it would be impossible for DerefMut::deref_mut to be invoked at all.
*value.lock().unwrap() += 1 works because now value.lock().unwrap() is a temporary variable without an explicit binding, so Rust is free to assign its mutability automatically.
The fact that Mutex contains an UnsafeCell inside is not related to this particular thing about DerefMut directly; however, it does mean that Mutex provides something called internal mutability, i.e. it allows one to mutate its contents through a shared reference. You can read more on it in the book.
I can't figure out what does this error in Rust mean:
error: lifetime of non-lvalue is too short to guarantee its contents can be safely reborrowed
What's a non-lvalue? (I suspect is not a right value).
I want to understand what the errror means and to be able to modify "objects" from a vector of mutable references.
This is a minimum test case to produce the error. I insert in a vector a mutable reference to a struct, and then I try to modify the pointed struct.
struct Point {
x: uint,
y: uint
}
fn main() {
let mut p = Point { x: 0, y: 0};
p.x += 1; // OK, p owns the point
let mut v: Vec<&mut Point> = Vec::new();
v.push(&mut p);
// p.x += 1 // FAIL (expected), v has borrowed the point
let p1:&mut Point = *v.get_mut(0); // ERROR, lifetime of non-lvalue...
// never reached this line
// p1.x += 1;
}
Let's go over what you're trying to do here:
let p1:&mut Point = *v.get_mut(0);
*v.get_mut(0) returns a mutable reference to first the mutable reference in the vector, then dereferences it. If this compiled, you would end up with two mutable references to the same object: one in the vector, the other in the p1 variable. Rust is rejecting this because it's not safe.
By far the best solution is to make the vector the owner of your Point objects. ie. use a Vec<Point> instead of a Vec<&mut Point.
If you need something more complicated, you can use a RefCell for dynamically checked borrowing:
use std::cell::RefCell;
struct Point {
x: uint,
y: uint
}
fn main() {
let p = RefCell::new(Point { x: 0, y: 0});
p.borrow_mut().x += 1;
let mut v: Vec<&RefCell<Point>> = Vec::new();
v.push(&p);
let p1 = v.get(0);
p1.borrow_mut().x += 1;
p.borrow_mut().x += 1;
}