Rust 编译器如何生成“此处发生不可变借用”?

Moo*_*oon 0 rust

我正在学习 Rust,以下代码来自在线书籍 The Rust Programming Language链接

fn first_word(s: &String) -> &str {
    let bytes = s.as_bytes();

    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &s[0..i];
        }
    }

    &s[..]
}

fn main() {
    let mut s = String::from("hello world");

    let word = first_word(&s);

    s.clear(); // error!

    println!("the first word is: {}", word);
}

Run Code Online (Sandbox Code Playgroud)

编译器如下:

fn first_word(s: &String) -> &str {
    let bytes = s.as_bytes();

    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &s[0..i];
        }
    }

    &s[..]
}

fn main() {
    let mut s = String::from("hello world");

    let word = first_word(&s);

    s.clear(); // error!

    println!("the first word is: {}", word);
}

Run Code Online (Sandbox Code Playgroud)

所以我认为“不可变的借用发生在这里”是在谈论&s而不是“让词”。但如果我改变

let word = first_word(&s);
Run Code Online (Sandbox Code Playgroud)

first_word(&s);
Run Code Online (Sandbox Code Playgroud)

编译器错误消失。所以这让我觉得“不可变的借用发生在这里”是在谈论“让词”而不是&s.

并且 iffirst_word的返回值仅依赖于另一个字符串(这意味着first_word根本不依赖于&s),如下所示:

fn first_word(s: &String) -> &str {
    println!("the input for first word is: {}", s);

    let s1 = "hi rust";
    let bytes = s1.as_bytes();

    for (i, &item) in bytes.iter().enumerate() {
        if item == b' ' {
            return &s1[0..i];
        }
    }

    &s1[..]
}
Run Code Online (Sandbox Code Playgroud)

编译器仍然在下面说:

| let word = first_word(&s);
|                       -- immutable borrow occurs here
Run Code Online (Sandbox Code Playgroud)

我对编译器实际上为生成“此处发生不可变借用”所做的工作感到非常困惑。

kmd*_*eko 7

你应该阅读完整的错误:

error[E0502]: cannot borrow `s` as mutable because it is also borrowed as immutable
  --> src/main.rs:18:5
   |
16 |     let word = first_word(&s);
   |                           -- immutable borrow occurs here
17 | 
18 |     s.clear(); // error!
   |     ^^^^^^^^^ mutable borrow occurs here
19 | 
20 |     println!("the first word is: {}", word);
   |                                       ---- immutable borrow later used here
Run Code Online (Sandbox Code Playgroud)

“不能借s为可变,因为它也被借为不可变”是错误消息,其他一切只是为了指出发生冲突的借用。


如果 first_word 的返回值仅取决于另一个字符串(这意味着 first_word 根本不取决于 &s),如下所示

这不太对。函数签名决定了生命周期。在您编辑的 中first_word,即使您返回的是str从静态字符串借来的,实际签名(没有省略生命周期)看起来像

fn first_word<'a>(s: &'a String) -> &'a str {
   ...
Run Code Online (Sandbox Code Playgroud)

返回的&str值绑定到 的生命周期,s而不管它究竟来自哪里。此示例仅展示了如何缩短具有静态生命周期的引用。并且由于返回值绑定到 的生命周期s,因此s被认为是借用的word