Rust 中结构字段的可变性
Mutability in fields for structs in Rust
我对 Rust 还是个新手,但我对可变性如何作用于结构中的字段存有疑问。特别是我们如何修改最初不可变的字段。例如:
struct Point {
x: isize,
y: isize,
}
impl Point {
fn new(x: isize, y: isize) -> Self {
Self { x, y }
}
fn set_x(&mut self, new_x: isize) {
self.x = new_x;
}
}
struct Line {
p: Point,
q: Point,
}
impl Line {
fn new(p: Point, q: Point) -> Self {
Self { p, q }
}
fn set_x_in_p(&mut self, new_x: isize) {
self.p.set_x(new_x);
}
}
fn main() {
// Both x and y are immutable
let p = Point::new(0, 0);
let q = Point::new(1, 1);
// Line IS mutable
let mut line = Line::new(p, q);
// Modifying point p (originally immutable) with a new x
line.set_x_in_p(999);
}
我们不能
let x = 3;
let y = &mut x; // does not work because x originally is immutable
那么,它是如何工作的?谢谢
当您声明 x
时,您是在使用 let
而不是 let mut
将其指定为不可变的。当您随后声明 y
并将其初始化为 &mut x
时,您正试图借用 x
。在 Rust 中,你永远不能做的一件事就是同时拥有共享所有权和可变性。
查看what Niko Matsakis has to say关于所有权的信息。
在您的示例中,p
和 q
确实是不可变的,但是随后您使用构造函数将它们移动到 Line
实例中,因为它们是按值传递的并且不' 实现 Copy
以启用隐式复制。这意味着原始绑定(p
和 q
)不再有效(编译器将阻止您使用它们)并且只能通过可变 line
绑定访问这些值,这允许改变它的成员。本质上,可变的不是 values,而是它们的绑定。例如,以下代码可用于重新绑定一个值以更改其可变性:
let x = String::from("hello world"); // using String as an example of a non-Copy type
let mut x = x; // this shadows the previous binding with a mutable one of the same name
x.make_ascii_uppercase(); // we can now mutate the string
let x = x; // shadow the mutable binding with an immutable one
println!("Result: {}", x);
此示例之所以有效,是因为我们可以直接控制该值,并且可以 move/bind 根据需要对其进行控制。引入引用会限制可以做的事情 - 例如,以下示例将不起作用:
let x = String::from("hello world");
let x_ref = &x; // create an immutable reference to x
let mut x_mut = x; // error - we can't move x while it's borrowed
let x_mut_ref = &mut x; // error - we can't create a mutable reference while any other references exist
我建议阅读 Rust 的 ownership and moves 页面示例,其中解释得很好。
我对 Rust 还是个新手,但我对可变性如何作用于结构中的字段存有疑问。特别是我们如何修改最初不可变的字段。例如:
struct Point {
x: isize,
y: isize,
}
impl Point {
fn new(x: isize, y: isize) -> Self {
Self { x, y }
}
fn set_x(&mut self, new_x: isize) {
self.x = new_x;
}
}
struct Line {
p: Point,
q: Point,
}
impl Line {
fn new(p: Point, q: Point) -> Self {
Self { p, q }
}
fn set_x_in_p(&mut self, new_x: isize) {
self.p.set_x(new_x);
}
}
fn main() {
// Both x and y are immutable
let p = Point::new(0, 0);
let q = Point::new(1, 1);
// Line IS mutable
let mut line = Line::new(p, q);
// Modifying point p (originally immutable) with a new x
line.set_x_in_p(999);
}
我们不能
let x = 3;
let y = &mut x; // does not work because x originally is immutable
那么,它是如何工作的?谢谢
当您声明 x
时,您是在使用 let
而不是 let mut
将其指定为不可变的。当您随后声明 y
并将其初始化为 &mut x
时,您正试图借用 x
。在 Rust 中,你永远不能做的一件事就是同时拥有共享所有权和可变性。
查看what Niko Matsakis has to say关于所有权的信息。
在您的示例中,p
和 q
确实是不可变的,但是随后您使用构造函数将它们移动到 Line
实例中,因为它们是按值传递的并且不' 实现 Copy
以启用隐式复制。这意味着原始绑定(p
和 q
)不再有效(编译器将阻止您使用它们)并且只能通过可变 line
绑定访问这些值,这允许改变它的成员。本质上,可变的不是 values,而是它们的绑定。例如,以下代码可用于重新绑定一个值以更改其可变性:
let x = String::from("hello world"); // using String as an example of a non-Copy type
let mut x = x; // this shadows the previous binding with a mutable one of the same name
x.make_ascii_uppercase(); // we can now mutate the string
let x = x; // shadow the mutable binding with an immutable one
println!("Result: {}", x);
此示例之所以有效,是因为我们可以直接控制该值,并且可以 move/bind 根据需要对其进行控制。引入引用会限制可以做的事情 - 例如,以下示例将不起作用:
let x = String::from("hello world");
let x_ref = &x; // create an immutable reference to x
let mut x_mut = x; // error - we can't move x while it's borrowed
let x_mut_ref = &mut x; // error - we can't create a mutable reference while any other references exist
我建议阅读 Rust 的 ownership and moves 页面示例,其中解释得很好。