如何从一个方法中改变结构体的字段?

115

我想要做这个:

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();
}

但是这段代码会抛出编译器错误:

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
2个回答

188
你需要使用&mut self而不是&self,并使p变量可变:
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();
}

在Rust中,可变性是继承的:数据所有者决定值是否可变。然而,引用并不意味着所有权,因此它们本身可以是不可变或可变的。您应该阅读官方书籍,其中解释了所有这些基本概念。

80
@VladimirMatveev 我只是想说,即使你阅读并学习了这本书,但如果之前从未接触过这些概念,直到你遇到实际相关情况时才能真正理解它。就像我一样,所以这些答案仍然非常有帮助 ;) - Aeolun
15
非常好的陈述。我翻阅了这本书,认为我理解了其中的概念,但是直到我开始实际开展Rust项目时才发现我并没有真正理解它。 - Syndog
2
这本书并不完美。 - dawid
1
文档(以及其子公司The Book)将有朝一日收购StackOverflow。 - David

19

通过使用 Cell<T>,您可以模拟字段级别的可变性:

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);
}

这将打印出y: Cell { value: 7 },我们已成功更新了y

此外,如果您正在使用nightly频道,则可以在.rs文件顶部声明#![feature(cell_update)],并在up()方法中使用以下语法:

impl Point {
    fn up(&self) {
        self.y.update(|x| x + 1);
    }
}
注意:上述功能是一个只在每晚版本中进行实验的API。
来自《Rust编程语言》 1.7 版本的 The Rust Programming Language

Box、Rc、Arc也适用吗? - mallwright
是的,可以。而且你可以将它们组合起来,例如:Rc<Cell<i32>> ... y: Rc::new(Cell::new(0)),. - silvioprog

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接