我有一个结构体:
pub struct Test {
pub x: i32,
pub y: i32,
}
我想要一个可以修改这个内容的函数 — 很容易:
pub fn mutateit(&mut self) {
self.x += 1;
}
这意味着在 mutateit
函数调用期间,整个结构体都是可变的,对吗?我只想改变 x
,不想改变y
。有没有办法只可变地借用 x
?
我有一个结构体:
pub struct Test {
pub x: i32,
pub y: i32,
}
我想要一个可以修改这个内容的函数 — 很容易:
pub fn mutateit(&mut self) {
self.x += 1;
}
这意味着在 mutateit
函数调用期间,整个结构体都是可变的,对吗?我只想改变 x
,不想改变y
。有没有办法只可变地借用 x
?
引用《Rust编程语言》:
Rust在语言层面上不支持字段可变性,因此你不能像这样写:
struct Point {
mut x: i32, // This causes an error.
y: i32,
}
你需要内部可变性,这在标准文档中有很好的描述:
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);
}
如果您想将其纳入函数中:
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);
}
#[derive(Debug)]
pub struct Test<'a> {
pub x: String,
pub y: &'a String,
}
impl<'a> Test<'a> {
pub fn mutateit(&mut self) {
self.x.insert(0, '#');
}
}
fn main() {
let mut foo = Test{x: "Hello".to_string(), y: &"World".to_string()};
// foo.y.insert(0, '+'); // This won't work! I can't mutate y because it is borrowed inside Test
let yref = foo.y; // If y wasn't behind a & this would cause a partial move
println!("{:?}", foo);
println!("{:?}", yref);
foo.mutateit(); // The borrow into yref would block this mutate, except its a reference not a borrow.
println!("{:?}", foo);
println!("{:?}", yref); // So my borrow lifetime is fine.
}
std::cell::Cell
实现了 !Sync,这意味着该结构体不能再在线程之间传递。因此,虽然内部可变性允许通过不可变引用来改变某些字段的值,但它也改变了语义并将Test
限制为严格单线程。 - Ted Klein Bergman