这绝对是一个有趣的话题。
它们很相似,但并不完全相同。resize()
是Vec
的成员函数。而rotate_right()
则是切片的方法。
Vec<T>
解引用为[T]
,因此大部分时间这并不重要。但实际上,当调用以下内容时:
vec.resize(vec.len(), 0);
转化为类似以下的代码:
<Vec<i32>>::resize(&mut vec, <Vec<i32>>::len(&vec), 0);
这个调用:
vec.rotate_right(vec.len());
更像是:
<[i32]>::rotate_right(
<Vec<i32> as DerefMut>::deref_mut(&mut vec),
<Vec<i32>>::len(&vec),
);
但是按什么顺序呢?
这是 MIR 的 rotate_right()
(大大简化):
fn foo() -> () {
_4 = <Vec<i32> as DerefMut>::deref_mut(move _5);
_6 = Vec::<i32>::len(move _7);
_2 = core::slice::<impl [i32]>::rotate_right(move _3, move _6);
}
这是resize()
的MIR(再次简化):
fn foo() -> () {
_4 = Vec::<i32>::len(move _5);
_2 = Vec::<i32>::resize(move _3, move _4, const 0_i32);
}
在
resize()
示例中,我们首先使用对
vec
的引用调用
Vec::len()
。这将返回
usize
。然后我们调用
Vec::resize()
,当我们没有未解决的对
vec
的引用时,因此可变地借用它是可以的!
但是,在
rotate_right()
中,首先我们调用
<Vec<i32> as DerefMut>::deref_mut(&mut vec)
。这将返回
&mut [i32]
,其生命周期与
vec
相关联。也就是说,只要这个引用(可变引用!)存在,我们就不允许使用任何其他对
vec
的引用。但是,然后我们尝试借用
vec
以传递给
Vec::len()
(虽然它是共享的,但无所谓),而我们仍然需要在稍后使用
deref_mut()
中的可变引用,以调用
<[i32]>::rotate_right()
!这是一个错误。
这是因为Rust定义了
操作数的评估顺序:
按照源代码中写作的从左到右的顺序计算多个操作数的表达式。
因为
vec.resize()
实际上是
(&mut *vec).rotate_right()
,所以我们首先评估解引用+引用,然后是参数:
let dereferenced_vec = &mut *vec;
let len = vec.len();
dereferencec_vec.rotate_right(len);
很明显这是违反借用规则的。
另一方面,vec.resize(vec.len())
在被调用者(vec
)上没有什么工作要做,因此我们首先评估vec.len()
,然后再进行调用本身。
解决这个问题就像将vec.len()
提取到新行(确切地说是新语句)一样容易,编译器也会给出提示。
[_]::rotate_right(DerefMut::deref_mut(&mut vec), Vec::len(&vec))
,而第二种方式转换为Vec::resize(&mut vec, Vec::len(&vec), 0)
。多出来的deref_mut
调用可能是借用检查器拒绝第一种情况的原因。 - Jmb