不可变和可变在调用“const”方法时借用“const”参数

cib*_*en1 2 rust

我不明白为什么 Rust在这段代码中抱怨(“不能借用为不可变的,因为也借用为可变的.len()”)(即使考虑到这是一个“常量/无害”的函数):

fn main() {
    
    let mut xs1: [i32; 5] = [ 10, 20, 30, 40, 50];

    let (slice1, slice2) = xs1.split_at_mut( (xs1.len()/2) ); // <----- ERROR

    println!( "{:?}", slice1 );
    println!( "{:?}", slice2 );

    

} // ()
Run Code Online (Sandbox Code Playgroud)

虽然拆分版本很好:

let aux = xs1.len()/2;
let (slice1, slice2) = xs1.split_at_mut( aux );
Run Code Online (Sandbox Code Playgroud)

这里面的道理是什么?

也许我错了,但我总是认为这两个表达式是“数学上等价的”。不仅len()应该是一个const方法,而且输入参数也split_at_mut()应该是const(用 C++ 的说法)。

八年后仍抱有这个疑问?

Mas*_*inn 6

也许我错了,但我总是认为这两个表达式是“数学上等价的”。

是的,但是这是借用检查器的问题,它并不完美,并且有局限性。

事实上,几乎所有没有漏洞的静态类型系统都会拒绝有效的程序:选择是要么拒绝有效的程序,要么接受无效的程序。

在这种情况下,正如 Sven Marnach 指出的那样,这是严格表达式求值顺序的产物:如果您对调用进行脱糖处理:

<[_]>::split_at_mut(&mut xs1, xs1.len()/2);
Run Code Online (Sandbox Code Playgroud)

你会得到同样的错误。

本质上,Rust 解释了

xs1.split_at_mut(xs1.len() / 2)
Run Code Online (Sandbox Code Playgroud)

作为

{
    let p1 = &mut xs1;
    {
        let p2 = xs1.len();
        {
            <[_]>::split_at_mut(p1, p2);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

不仅len()应该是一种const方法

...它是什么?

而且 for 的输入参数也split_at_mut()应该是 const (用 C++ 的说法)。

这个想法与 Rust 无关,split_at_mut它拥有其(非自身)参数的所有权。


Sve*_*ach 5

这主要是表达式求值顺序的副作用。在评估 call 时xs1.split_at_mut((xs1.len()/2)),第一步是确定实际调用的方法,其中涉及确定接收者的类型。由于split_at_mut需要一个&mut [i32],xs1此时会可变地借用。对 的调用xs1.len()稍后发生,但此时我们已经有了可变借用,因此不可变借用是不可能的。

如果您首先将长度存储在变量中,则不可变借用首先发生,并且它在表达式的末尾结束,因此它不再与可变借用重叠。