Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot assign to `self.x` because it is borrowed

I have 2 functions:

// A simple struct
struct S {
    w: u8,
    h: u8,
    x: Vec<u8>,
    y: Vec<u8>,
}

// Implementation of the struct S
impl S {
    // Seems to work
    fn new(_w: u8, _h: u8, _x: &Vec<u8>, _y: &Vec<u8>) -> S {
        S {
            w: _w,
            h: _h,
            x: _x.clone(),
            y: _y.clone(),
        }
    }

    fn calc(&mut self) {
        let mut min_x = self.x.iter().min().unwrap();
        let mut max_x = self.x.iter().max().unwrap();
        let mut min_y = self.y.iter().min().unwrap();
        let mut max_y = self.y.iter().max().unwrap();

        // Here's the line that gives the error
        self.x = self.x
            .iter()
            .map(|v| norm_value(*v, *min_x, *max_x, 0, self.w))
            .collect();
    }
}

fn norm_value<A, B, C, D, E>(_: A, _: B, _: C, _: D, _: E) -> ! { panic!() }
  1. new makes a new S object. This seems to work, but correct me if I did something horribly wrong and just happens to work.

  2. calc tries to modify the members x and y.

The compiler reports this error:

error[E0506]: cannot assign to `self.x` because it is borrowed
  --> src/main.rs:28:9
   |
22 |           let mut min_x = self.x.iter().min().unwrap();
   |                           ------ borrow of `self.x` occurs here
...
28 | /         self.x = self.x
29 | |             .iter()
30 | |             .map(|v| norm_value(*v, *min_x, *max_x, 0, self.w))
31 | |             .collect();
   | |______________________^ assignment to borrowed `self.x` occurs here

Where did I borrow self.x? I am new to Rust but things like this make no sense.

like image 734
DimChtz Avatar asked Sep 02 '25 15:09

DimChtz


1 Answers

All of the variable bindings at the beginning of calc return shared references (&u8) to self.x and self.y, which means you can no longer mutate them.

In order to not be bound by these borrows at the point of the last assignment you can clone() the references to obtain regular u8s:

let mut min_x = self.x.iter().min().unwrap().clone();
let mut max_x = self.x.iter().max().unwrap().clone();
let mut min_y = self.y.iter().min().unwrap().clone();
let mut max_y = self.y.iter().max().unwrap().clone();

I'm not sure if this solves all your issues, because you didn't provide the signature of norm_value.

As for the new method, you'll probably want to change the signature to obtain them by value instead of by reference:

fn new(w: u8, h: u8, x: Vec<u8>, y: Vec<u8>) -> S {
    S { w: w, h: h, x: x, y: y }
}

let s = S::new(10, 10, vec![1, 2, 3, 4], vec![52, 10, 23, 56]);

Note that I removed the underscores - you don't need to prepend the function arguments with them, if you remove them it will still be clear to the compiler. Prepending variable identifiers with underscores is usually used to silence the #[warn(unused_variables)] warnings.

like image 56
ljedrz Avatar answered Sep 05 '25 15:09

ljedrz