16

I have a struct:

pub struct Test {
    pub x: i32,
    pub y: i32,
}

I'd like to have a function that mutates this — easy:

pub fn mutateit(&mut self) {
    self.x += 1;
}

This makes the entire struct mutable for the duration of the function call of mutateit, correct? I only want to mutate x, and I don't want to mutate y. Is there any way to just mutably borrow x?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366

1 Answers1

19

Citing The Book:

Rust does not support field mutability at the language level, so you cannot write something like this:

struct Point {
    mut x: i32, // This causes an error.
    y: i32,
}

You need interior mutability, which is nicely described in the standard docs:

use std::cell::Cell; 

pub struct Test {
    pub x: Cell<i32>,
    pub y: i32
}

fn main() {
    // note lack of mut:
    let test = Test {
        x: Cell::new(1), // interior mutability using Cell
        y: 0
    };

    test.x.set(2);
    assert_eq!(test.x.get(), 2);
}

And, if you wanted to incorporate it in a function:

impl Test {
    pub fn mutateit(&self) { // note: no mut again
        self.x.set(self.x.get() + 1);
    }
}

fn main() {
    let test = Test {
        x: Cell::new(1),
        y: 0
    };

    test.mutateit();
    assert_eq!(test.x.get(), 2);
}
ljedrz
  • 20,316
  • 4
  • 69
  • 97
  • 3
    While this works, it should be noted that `std::cell::Cell` implements [!Sync](https://doc.rust-lang.org/std/cell/struct.Cell.html#impl-Sync), meaning that the struct can no longer be passed between threads. So while interior mutability allow certain fields to be mutable through a immutable reference, it also change the semantics and restricts `Test` it to be strictly single-threaded. – Ted Klein Bergman Apr 25 '21 at 15:35