112

I want to do this:

struct Point {
    x: i32,
    y: i32,
}

impl Point {
    fn up(&self) {
        self.y += 1;
    }
}

fn main() {
    let p = Point { x: 0, y: 0 };
    p.up();
}

But this code throws a compiler error:

error[E0594]: cannot assign to field `self.y` of immutable binding
 --> src/main.rs:8:9
  |
7 |     fn up(&self) {
  |           ----- use `&mut self` here to make mutable
8 |         self.y += 1;
  |         ^^^^^^^^^^^ cannot mutably borrow field of immutable binding
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
alxkolm
  • 1,911
  • 2
  • 14
  • 11

2 Answers2

185

You need to use &mut self instead of &self and make the p variable mutable:

struct Point {
    x: i32,
    y: i32,
}

impl Point {
    fn up(&mut self) {
        // ^^^ Here
        self.y += 1;
    }
}

fn main() {
    let mut p = Point { x: 0, y: 0 };
    //  ^^^ And here
    p.up();
}

In Rust, mutability is inherited: the owner of the data decides if the value is mutable or not. References, however, do not imply ownership and hence they can be immutable or mutable themselves. You should read the official book which explains all of these basic concepts.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Vladimir Matveev
  • 120,085
  • 34
  • 287
  • 296
  • 79
    @VladimirMatveev I just want say that even if you read and worked through the book, having never seen these concepts before, it might not make much sense until you run into an actual situation where it is relevant. As it was for me, so these answers are still really helpful ;) – Aeolun Aug 18 '17 at 09:21
  • 14
    @Aeolun - Very well said. I went through The Book, and thought I understood the concept, but discovered I really didn't until I started working on an actual Rust project. – Syndog Oct 08 '18 at 13:19
  • 2
    The book is not perfect. – dawid Mar 15 '21 at 01:19
18

By using Cell<T> you can emulate field-level mutability:

use std::cell::Cell;

struct Point {
    x: i32,
    y: Cell<i32>,
}

impl Point {
    fn up(&self) {
        self.y.set(self.y.get() + 1);
    }
}

fn main() {
    let p = Point { x: 0, y: Cell::new(0) };
    p.up();
    println!("y: {:?}", p.y);
}

This will print y: Cell { value: 7 } and we've successfully updated y.

Additionally, if you are using nightly channel, you can declare #![feature(cell_update)] on top of your .rs file and use the following syntax inside your up() method:

impl Point {
    fn up(&self) {
        self.y.update(|x| x + 1);
    }
}

Note: This feature above is a nightly-only experimental API.

From The Rust Programming Language at Rust 1.7.

silvioprog
  • 580
  • 1
  • 8
  • 18