我有一个关于Rust中的move语义的问题,在我的理解中,Rust中的“mut”关键字是为了使一些变量变得可变,也就是说,可变的变量可以重新绑定到另一个值上;然而这种可变性只适用于绑定。所以,如果我真的想改变变量的值,那么我应该像这样使用“&mut”关键字:
let mut two = 2;
let t = &mut two;
*t += 1;// update the value of two, not only bind t to another values
print!("{}", t); // here, t is 3
然而,在使用结构体的情况下,情况似乎不是这样。
下面是一个示例代码(https://doc.rust-lang.org/book/ch05-01-defining-structs.html):
let mut user1 = User {
email: String::from("someone@example.com"),
username: String::from("someusername123"),
active: true,
sign_in_count: 1,
};
user1.email = String::from("anotheremail@example.com");
为什么我可以重写user 1的“email”字段?看起来不像是重新绑定user 1。
3条答案
按热度按时间dwthyt8l1#
我认为您的问题源于围绕
mut
作为关键字的一个小混淆,打个比方可能会有所帮助。假设我有一辆车,我们先来定义一下什么是车:
可变定义
让我们定义一下我的车
这是我的车,我把它定义为一个可变的实体(
let mut
),所以如果我想的话,我可以给它加油,把它调成蓝色这取决于变量本身的定义。如果我的车只有
let
,我就无法做到这一点。用let mut
分配变量表示它可以在所有字段中修改,无论谁有:参考/借用
然后我决定去加油站加油,我把车借给服务员,让他们帮我加油:
如果他愿意的话,他可以开车去喷漆店把车换个颜色,因为整辆车暂时都是他的。同样值得注意的是,虽然他有这辆车,但 * 我不能对它做任何事情 *。我把它借给了他,在他归还
borrow
之前,它就是他的。当然,现在除了他拥有汽车之外,任何人都可以偷看我的汽车,欣赏它的颜色(或者它的轮子数量),
my_car
的所有公共属性都可以被任何拥有不可变借位的人公开检查。然后我决定尝试另一个加油站,结果发现它相当不诚实:
我的车是粉红色的泡泡糖!
我们可以通过让某人看管汽车来避免这种情况。如果我们给予某人一个不可变的
&my_car
借用,然后试图再次去那个可怕的加油站,程序将根本无法编译(example here)lzfw57am2#
我想你对变量的工作原理感到困惑。变量就像可以存储数据的杯子,对于像rust这样的强类型语言来说,它们只能容纳一种类型的数据。
因此,当你声明一个值时,基本上你是在指示计算机在内存中分配一些空间:
在上面的例子中,基本上你是在说"电脑,给我一个足够大的杯子来装u32数据(32 bits)"。
然后计算机给你这个杯子,在我们的例子中x是所有者,
x
是你如何持有这个杯子,换句话说,内存空间的所有者。现在让我们用适当的数据填充杯子:
一旦强大的计算机为x保留了这个杯子,它就属于x,直到x放弃所有权:
一旦内存空间被释放,计算机就可以把它给其他变量.
您可以按如下方式检查存储空间的地址:
当你初始化x时,计算机会给你这个内存空间。这就是资源获取即初始化(RAII)在起作用:
出现编译器错误:
但是如果你在初始化之后检查地址,它编译时不会有任何错误:
声明变量时,您与编译器有一个契约。
mut
是该契约的条款之一。如果不使用
mut
关键字,你就等于说,一旦我把杯子装满(初始化一个变量),我就永远不会改变杯子里的东西(内存空间中的x个点)。但是如果你使用
mut
关键字,你的合约说你可以在那个内存空间中放入任何值,只要它是正确的类型。在这两种情况下,内存空间的所有者都是x。可变性与所有权无关。
现在,关于你的例子:
在第二行中,你取了一个对变量
two
的可变引用。换句话说,t借用了x所指向的。在下一行中,你用3来填充杯子。因为你使用了可变引用,所以你必须在下一行*t += 1;
中解引用。这将打印:
two
是所有者,t只是借用:同样,可变性与所有权无关,Rust对借用可变值进行了限制,以消除混乱,因为当多个变量可以改变杯中的内容时,很容易失去对谁做什么的控制。
在User类型的情况下,如果你把
user1
值初始化为可变的,你可以改变你在它的属性中存储的内容,就像杯子容纳其他杯子,或者指针指向堆中存储的其他杯子一样。sczxawaw3#
不,你不需要为了改变一个变量而可变地借用它。
可以很好地工作,当你想让你的函数修改它所接收的结构体时,可变的借位是很有用的,如果一个函数foo把它所接收的结构体的所有权作为参数,而不是接收一个可变的引用,那么当函数foo返回时,这个结构体的生命周期就结束了,你通常不希望这样,这就是为什么要给函数传递一个可变的引用。可变引用是一些函数的返回类型,如HashMap的get函数返回一个可变引用的可选项,它是一个可变引用的可选项。不是自己的类型,因为您希望HashMap继续拥有数据,并且您还希望允许get函数的调用者能够改变HashMap拥有的数据。假设HashMap函数通过复制其数据返回一个可选的拥有类型,在这种情况下,调用者所做的任何改变都不会影响存储在HashMap中的数据,因为调用者已经收到了数据的副本。