Rust如何知道变量是否可变?

时间:2017-09-17 16:36:21

标签: rust mutable

以下C#代码编译良好:

static readonly List<int> list = new List<int>();
static void Main(string[] args)
{
    list.Add(1);
    list.Add(2);
    list.Add(3);
}

如果我在Rust中编写类似的代码,它将无法编译,因为它无法将不可变的v作为可变的来源:

let v = Vec::new();
v.push(1);
v.push(2);
v.push(3);

push函数如何知道v是不可变的?

2 个答案:

答案 0 :(得分:8)

默认情况下,所有变量不可变。您必须explicitly tell the compiler which variables are mutable let mut v = Vec::new(); v.push(1); v.push(2); v.push(3); 关键字:

&mut self

Vec::push被定义为需要对向量(fn push(&mut self, value: T) )的可变引用:

fn push(&mut Vec<T>, value: T)

这使用method syntax,但在概念上与:

相同
Python 3.6.1 |Anaconda 4.4.0 (x86_64)| (default, May 11 2017, 13:04:09) 
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.57)] on darwin
Type "help", "copyright", "credits" or "license" for more information.

我强烈建议您阅读The Rust Programming Language, second edition。它涵盖了这个初学者问题以及您将要遇到的许多其他初学者问题。

答案 1 :(得分:3)

在Rust中,默认情况下绑定是不可变的。所以您可能会认为以下内容是等效的:

readonly List<int> list = new List<int>(); // C#
let list = Vec::new();                     // Rust

这些:

List<int> list = new List<int>(); // C#
let mut list = Vec::new();        // Rust

但是,正如你所知,情况并非如此。

在C#版本的Add方法中,没有关于用于调用它的绑定的信息。 Add方法无法声明它会改变其数据,因此C#编译器无法阻止您将引用传递给readonly绑定。 readonly关键字会阻止您使用全新的list覆盖List绑定,但这并不会阻止您更改所拥有的数据。 C#阻止您更改readonly绑定的值,但在这种情况下,值是指向数据的指针,而不是数据本身。

在Rust中,如果方法需要改变底层数据,则必须将其第一个参数声明为self&mut self

对于self,数据移动到方法中,您不能再使用原始绑定。如果方法更改数据并不重要,因为调用者不能再使用该绑定。

在可变引用&mut self的情况下,如果原始绑定也是可变的,Rust将只允许您创建它。如果原始绑定是不可变的,那么这将产生编译错误。如果v.push是不可变的,则无法致电v,因为push期望&mut self

这可能是限制性的,因此Rust提供的工具可以让您微调此行为,以准确编码您需要的安全保证。如果您想获得接近C#行为的东西,可以使用RefCell包装器(或其他几种包装器类型之一)。 RefCell<Vec<T>>本身不必是可变的,因为函数能够解包它并修改里面的Vec