为什么Rust允许升级/降级可变性?

3
在 Rust 中,您可以升级一个不可变变量:
let v = Vec::new(); // Immutable
let mut v = v;      // Mutable
v.push("hi");       // Succeeds

或者将可变变量降级:

let mut v = Vec::new();   // Mutable
let v = v;                // Immutable
v.push("hi");             // Won't compile

我的问题是-为什么?

据我所知,用于存储变量值的底层内存从未是不可变的。技术上每个内存地址都可以被写入。不可变性是一种人为的限制,由某些人(例如内核)强加给我们,或者我们自己强加给自己。

当我说:

let v = vec!["a", "b", "c"];

我想要一个变量在内存中保存这些值,且不希望它被后续的任何代码更改。如果我在某个时刻尝试更改此变量,则应该报错。这是我定义的约束条件。
如果稍后只需要执行以下操作:
let mut v = v;

使其可变并更改它,这似乎违背了不可变变量的整个目的。在那一点上,您可能会选择使所有变量可变(像Python一样),因为不可变性不能得到保证。不仅如此,程序员可能会对不可变性的保证产生错误的认识,并根据这种假设犯错。
至少对于常量,存在不可变性的保证。如果您可以随时将其变为可变的,则普通不可变变量的目的不清楚。

6
你并不是在“升级”,而是将一个旧的值移动到一个新的可变值中,并使用相同的名称。 - undefined
1
需要注意的是,只有在你拥有它们的情况下,才能将不可变的值“升级”为可变的。例如,你不能将一个不可变的“引用”升级为可变的引用。如果你拥有一个值,你可以随意处理它 - 你可以在任何时候将其移动到(不)可变绑定中。不可否认的是,这使得不可变绑定并不像不可变引用那样重要。如果你想指定一个值是永久可变的,请使用常量。 - undefined
2个回答

5

In rust, you can upgrade an immutable variable:

let v = Vec::new(); // Immutable
let mut v = v;      // Mutable
v.push("hi");       // Succeeds

这不是升级一个变量。你正在创建一个名为v的变量并将其移动到另一个同样称为v的变量中。原始的v不再可访问。在调试模式下,生成的代码很可能对于第一个和第二个v有两个完全不同的(堆)内存地址。

至于降级,情况也是一样的。

这似乎违背了不可变变量的整个目的。

一旦您移动了一个值,您就不能再使用它,如果存在对该值的引用,则无法移动该值。因此,您永远不会出现对现在是不可变的东西进行可变引用的情况。


我以为那就是发生的事情,但我不确定。谢谢你的确认。然而,这似乎是一个没有区别的区分。显然,“将可变绑定降级为不可变在Rust中非常常见”--https://dev59.com/1lQJ5IYBdhLWcg3wGB1N#54595440。几乎像是编译器应该注意并阻止的事情,就像它对许多其他技术上可能但不应该做的情况一样(比如所有权)。不能对一个不可变变量进行可变引用并不是问题所在。问题在于程序员不知道为什么一个本应该是不可变的变量发生了改变。 - undefined

-1
Rust允许重新定义变量。所以在你的例子中,你声明了一个新变量v,并将向量复制到其中:
let v = Vec::new(); // Immutable
let mut v = v;      // New Mutable <—-
v.push("hi");       // Succeeds

因为向量实现了复制特性。
通过借用作为引用,您可以使样本按照您的意图工作(或者不工作)。
let v = Vec::new(); // Immutable
let &mut v = v;      // Doesnt compile
v.push("hi");

3
向量不实现 Copy。相反,向量被移动到一个新的变量绑定中。另外,在第二个代码片段中你可能想表达的是 let v = &mut v; - undefined
2
第二个片段无法编译,因为它的语法无效。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接