将“mut”放在变量名称之前和放在“:”之后有什么区别?

What's the difference between placing "mut" before a variable name and after the ":"?

提问人:Jimmy Lu 提问时间:2/18/2015 最后编辑:Peter HallJimmy Lu 更新时间:12/12/2022 访问量:22014

问:

以下是我在 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>) { /* ... */ }
变量 语法 参考 可变

评论

4赞 legends2k 9/22/2020
对于 C++ 程序员:区别类似于指针常量针常量

答:

139赞 Shepmaster 2/18/2015 #1

mut foo: T表示您有一个名为 的变量。您可以更改变量所指的内容:fooT

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

请注意,只有引用才有意义 - 不是有效的语法。如果有意义,还可以组合两个限定符 ()。&mutfoo: mut Tlet mut a: &mut T

评论

16赞 Jimmy Lu 2/18/2015
明白了。我想这就像在 C++ 中,您可以拥有 vs。 实现不同的事情。int const*int *const
4赞 Scott Olson 2/18/2015
@Shepmaster 你可能想在绑定上添加它,允许你在结构内部进行变异(如果它是一个结构)。mut
10赞 Scott Olson 2/19/2015
@BeyondSora 不要认为是 ,而是 。该关键字通常不用于类型,但有一种称为 的引用类型。&mut Type&(mut Type)(&mut) Typemut&mut
3赞 didierc 2/19/2015
@ScottOlson 所以,你说的是这只是一个“方便”的符号,以避免引入一个新的关键字,但实际上它与 lhs 通常的关键字是一个不同的概念?&mutmut
3赞 Scott Olson 2/19/2015
@didierc是的。你可以把 和 看作是 和 的糖(我刚刚编造的类型)。&T&mut TRef<T>RefMut<T>
169赞 anderspitman 4/17/2015 #2

如果您来自 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 采取“白名单”方法,如果你想让某些东西可变,你必须明确地说出来。

评论

5赞 trent 10/12/2019
这是一张很棒的桌子。值得一提的是,引用也类似于 C 语言中的指针:它们可能不是别名。 引用没有这样的约束,也没有类似于非限定指针的引用类型。&mut TT* restrict&TrestrictT*
2赞 Kresten 10/10/2020
我没有 C 背景,但我仍然认为这比公认的答案更能解释它(带有评论),有时更简单总比更长更好。
0赞 nbro 12/30/2022
对于忘记 C/C++ 规则的人
39赞 George 5/24/2021 #3

以下自然语言翻译似乎为我澄清了事情......

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}

where

  • {binds mutably} means the binding can be reassigned
  • {mutable value} means the value's contents can change
  • To be able to mutate a value you need both a mutable binding and a mutable value

Note:

参考可变性与目标可变性

引用变量(如 中 )是独立于它所指向的目标变量的变量。特别是,在堆栈上有自己的位置和可变性权限。因此,如果像这里一样是不可变的,那么它就不能被重新赋值以指向其他变量。该限制与通过它改变目标的能力是分开的,如 ;目标是一个具有自身可变性权限的不同变量。但是,如果 是可变的,如 ,那么它确实可以重新赋值以指向其他一些类似类型的变量:。xlet x = &mut yyxx*x = some_valuewlet mut w = &mut pw = &mut z

评论

0赞 user782220 6/19/2022
您确定“为了能够更改值,您需要一个可变绑定和一个可变值”这句话吗?以下对我有用 ' fn main() { let mut value = 4; println!(”{}“, 值);设 x = &mut 值;println!(“{}”, x);*x = 5;println!(“{}”, x);} `
0赞 George 12/9/2022
value是一个位置。位置内容是可变的。它目前包含 . 是堆栈上的一个位置。位置内容是不可变的。它当前包含的地址为 。地址类型允许更改该位置内容。因此,虽然你不能改变,但你可以改变它所指的内容。这些约束是在编译时施加的,以防止某些代码,特别是变量在具有可变引用时将不可用:一次只能有一个对变量的可变引用。4xvaluex*xsafe rustvaluex
0赞 user782220 12/12/2022
但是$x$ 不是可变绑定是我的观点。
0赞 George 12/12/2022
我明白你的意思。引用不是对目标的绑定。引用是一个单独的变量,具有自己的可变性权限。具体来说,创建为位于堆栈上的不可变指针变量,并包含变量的地址,在这种情况下,该位置是可变的。另一方面,是一个可变的指针。特别是,重新分配 ,现在是可能的,而以前则不是。let x = &mut yxylet mut x = &mut yx = &mut z
1赞 RBF06 7/6/2022 #4

引用类型的可变变量

当你有

let mut x: &T = value;

这意味着 是引用 的实例的变量,就好像将实例的内存地址存储在 的值中一样。这个引用(即“内存地址”)是这个上下文中可变性的主题:可以修改为引用一个不同的实例,如下所示:xTTxxT

x = some_other_T_instance;

但是引用对象(即引用的实例的值)不能通过以下方式更改:Txx

// Illegal
*x = a_different_value;

可变引用类型的不可变变量

当你有

let x: &mut T = value;

这意味着 that 是一个变量,它引用了 的可变实例。在这种情况下,所指对象(即实际值)是可变性的主体。可以通过这样的引用进行修改xT

*x = some_other_value;

但是引用本身(即变量中的“内存地址”)不能:x

// illegal
x = a_different_value;