以下是我在 Rust 文档中看到的两个函数签名:
fn modify_foo(mut foo: Box<i32>) { *foo += 1; *foo }
fn modify_foo(foo: &mut i32) { *foo += 1; *foo }
为什么 mut
放置位置不同?
似乎第一个函数也可以声明为
fn modify_foo(foo: mut Box<i32>) { /* ... */ }
如果您来自C/C++,那么基本上可以这样理解:
// Rust C/C++
a: &T == const T* const a; // can't mutate either
mut a: &T == const T* a; // can't mutate what is pointed to
a: &mut T == T* const a; // can't mutate pointer
mut a: &mut T == T* a; // can mutate both
您会注意到这两者是相反的。C/C++采用“黑名单”方法,如果您想要某些东西不可变,则必须明确声明,而Rust采用“白名单”方法,如果您想要某些东西可变,则必须明确声明。
&mut T
引用也类似于 C 语言中的 T* restrict
指针:它们可能不会被别名引用。而 &T
引用没有此限制,并且没有与未带有 restrict
限定符的 T*
指针相对应的引用类型。 - trentmut foo: T
表示你有一个名为 foo
的变量,它是一个类型为 T
的变量。你可以改变这个变量所引用的内容:
let mut val1 = 2;
val1 = 3; // OK
let val2 = 2;
val2 = 3; // error: re-assignment of immutable variable
struct Monster { health: u8 }
let mut orc = Monster { health: 93 };
orc.health -= 54;
let goblin = Monster { health: 28 };
goblin.health += 10; // error: cannot assign to immutable field
foo: &mut T
表示您有一个变量引用(&
)一个值,并且您允许更改(mut
)所引用的值(包括字段,如果它是一个结构体):
let val1 = &mut 2;
*val1 = 3; // OK
let val2 = &2;
*val2 = 3; // error: cannot assign to immutable borrowed content
&mut
只能用于引用类型 - foo: mut T
不是有效的语法。当有意义时,您也可以组合这两个限定符(let mut a: &mut T
)。int const*
和 int *const
来实现不同的功能。 - Jimmy Lumut
绑定,这样就可以在结构体内部进行变异(如果它是一个结构体)。 - Scott Olson&mut Type
看作是&(mut Type)
,而应该看作是(&mut) Type
。关键字mut
通常不用于类型中,但是有一种叫做&mut
的引用类型。 - Scott Olson&mut
只是为了避免引入新关键字而使用的方便记法,但实际上它和左侧通常的 mut
关键字是不同的概念? - didierc&T
和&mut T
视为sugar
(我刚刚想出来的类型)的Ref<T>
和RefMut<T>
。请注意,这并不改变原始含义。 - Scott Olson以下自然语言翻译似乎帮我搞清楚了一些事情...
let x = value;
x {binds immutably} to {immutable value}
let mut x = value;
x {binds mutably} to {possibly mutable value}
let x = &value;
x {binds immutably} to {a reference to} {immutable value}
let x = &mut value;
x {binds immutably} to {a reference to} {mutable value}
let mut x = &value;
x {binds mutably} to {a reference to} {immutable value}
let mut x = &mut value;
x {binds mutably} to {a reference to} {mutable value}
什么是可变绑定和可变值:
{binds mutably}
表示该绑定可以被重新赋值{mutable value}
表示该值的内容可以更改注意:
参考可变性 vs 对象可变性
像 x
这样的引用变量,在 let x = &mut y
中,它是一个与其指向的目标变量 y
分离的变量。特别地,x
有自己在堆栈中的位置和可变性权限。因此,如果像这里一样,x
是不可变的,则不能将其重新赋值为指向其他变量的指针。该限制与通过它来改变目标的能力无关,如 *x = some_value
;目标是具有自己的可变性权限的独立变量。然而,如果像 let mut w = &mut p
这样,w
是可变的,则确实可以将其重新赋值为指向其他类型相似的变量:w = &mut z
。
fn main() {
let mut value = 4;
println!("{}", value);
let x = &mut value;
println!("{}", x);
*x = 5;
println!("{}", x);
}
- user782220value
是一个位置。该位置的内容是可变的。它当前包含 4
。x
是堆栈上的位置。该位置的内容是不可变的。它当前包含对 value
的地址。地址类型允许修改该位置内容。因此,虽然您无法更改 x
,但可以更改其所指向的内容 *x
。这些限制在 safe rust
中在编译时强制执行,防止某些代码使用变量 value
在 x
有可变引用时不可用:同一时间只能有一个可变引用变量。 - Georgelet x = &mut y
创建了一个不可变指针变量 x
,位于堆栈上,并包含变量 y
的地址,在这种情况下,该位置是可变的。另一方面,let mut x = &mut y
是一个可变指针。特别地,重新赋值 x = &mut z
现在是可能的,而之前则不行。 - George当您拥有一个
let mut x: &T = value;
x
是一个变量,它“引用”T
的一个实例,就好像将T
实例的内存地址存储在x
的值中一样。这个“引用”(即“内存地址”)是这种情况下可变性的主题:可以通过以下方式修改x
以引用不同的T
实例:x = some_other_T_instance;
但是x
无法通过赋值改变引用(即T
实例的值):
// Illegal
*x = a_different_value;
当你拥有一个
let x: &mut T = value;
x
是一个变量,它引用了一个可变的T
实例。在这种情况下,引用对象(即实际值)是可变性的主题。可以通过引用像这样修改它。*x = some_other_value;
但是参考本身(即变量 x
中的“内存地址”)无法:
// illegal
x = a_different_value;
const
和指向对象的指针const
之间的区别。 - legends2k