你很接近了,但你遗漏了一个关键的细节.
在Rust中,赋值(包括函数参数的赋值)由值moving进行,除非值的类型实现Copy
,在这种情况下它被复制.在C++中,您必须使用std::move()
请求MOVE(在它不是隐式的情况下),而在Rust中,对于不能复制的值,MOVE是automatic,并且MOVE会腾出原始变量,因此再次try 从它读取会导致编译时错误.
Copy
特征是为所有共享引用(&T
)实现的,但它是为可变引用(&mut T
)实现的not.
然而,在这种特殊情况下,编译器做了一件狡猾的事情.如果移动了引用,那么在调用func()
之后,s
将处于"Moving From"状态,因此您可能会认为不能再使用它了……但你可以的!
func(s);
func(s);
这将进行编译.那到底是怎么回事?
编译器会在此处插入一个reborrow,就好像您已经编写了以下代码:
func(&mut *s);
这种构造要求编译器not消费引用s
,并且取而代之地重新borrow 其引用.(当传递对函数的引用时,这会隐式发生,就像这里所发生的那样,但在其他情况下,它是not隐式的,您必须显式地重新borrow .)
但如果是这样的话,同一个变量word
有两个可变引用,这违反了Rust的定义规则.
啊,但这并不是quite%的规则.规则是,在任何给定时刻,值可以是:
- 可读任意数量的名称,or
- 可写入at most one name.
这并不意味着不能有两个对同一个值的可变引用,它只是意味着一次只能有一个可用引用.
在您的代码中,main()
在重新borrow s
之后将控制权转移给func()
.这意味着s
在s_ref
离开之前不能使用--但它could not possibly be used直到s_ref
离开,因为func()
必须在s
可以再次使用之前返回.
因此,如您所见,这并不违反Rust的别名规则.调用func()
时,可以使用s_ref
将值word
写入,但在函数返回之前,不能使用s
将其写入.那么s
就可以再次使用了.
我们可以通过以下两个程序来演示这一点:
fn func(s_ref: &mut str) {}
fn main() {
let mut word = "hello".to_string();
let s: &mut str = &mut word;
let s2: &mut str = &mut *s;
func(s2);
func(s);
}
这是编译的!我们将s
重新借入s2
,但我们在停止使用s2
之前不会使用s
.编译器自己计算出这一点(见non-lexical lifetimes).
然而,如果我们交错使用,那么我们就有一个问题:
fn func(s_ref: &mut str) {}
fn main() {
let mut word = "hello".to_string();
let s: &mut str = &mut word;
let s2: &mut str = &mut *s;
func(s);
func(s2);
}
现在,编译器会抱怨:
error[E0499]: cannot borrow `*s` as mutable more than once at a time
--> src/main.rs:8:10
|
6 | let s2: &mut str = &mut *s;
| ------- first mutable borrow occurs here
7 |
8 | func(s);
| ^ second mutable borrow occurs here
9 | func(s2);
| -- first borrow later used here
在第6和第9行之间,s
和s2
都被认为是可用的,这是不允许的.
正如您所看到的,对同一个值有多个可变引用是没有问题的.但是,它们的使用不允许重叠.只要它们不重叠,就没有问题.