【问题标题】:How does the rust compiler generate "immutable borrow occurs here"?rust 编译器如何生成“这里发生不可变借用”?
【发布时间】:2020-10-19 10:50:47
【问题描述】:

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

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);
}

编译器如下:

| let word = first_word(&s);
|                       -- immutable borrow occurs here

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

let word = first_word(&s);

first_word(&s);

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

如果first_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[..]
}

编译器仍然在下面说:

| let word = first_word(&s);
|                       -- immutable borrow occurs here

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

【问题讨论】:

  • 暂时忽略错误消息的实际内容,只关注“错误”/“无错误”。你明白为什么第一个 sn-p 是错误的(错误),但是如果你将let word = first_word(&s); 更改为只是first_word(&s);,它就会变得正确(没有错误)?我完全渴望了解借用检查器如何得出结论;但是,如果您不了解它试图保护您免受什么侵害,那么该过程将看起来像很多武断的 gobbledygook。 (老实说,有时确实如此。)
  • 你可以通过简单地假设借用检查器具有完美的信息并且总是正确的,并尝试从它向后工作以查看你的代码如何违反规则以导致未定义的行为,从而在 Rust 中走得更远。这个假设并不完全正确,因为借用检查器不理解的一些事情是可以的,但 this 案例不是其中之一;即,在s.clear() 之后使用word 确实会在此处导致UB。

标签: rust


【解决方案1】:

你应该阅读完整的错误:

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

“不能将s 借用为可变的,因为它也被借用为不可变的” 是错误消息,其他所有内容都只是为了指出冲突借用发生的位置。


如果 first_word 的返回值只依赖于另一个字符串(这意味着 first_word 根本不依赖 &s)如下

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

fn first_word<'a>(s: &'a String) -> &'a str {
   ...

返回的&amp;str 绑定到s 的生命周期,无论它来自何处。此示例仅显示如何缩短具有静态生命周期的引用。并且由于返回值绑定到s的生命周期,s被认为是word借用的。

【讨论】:

  • Nit:first_word 的生命周期内容同时表示输出仅在 s 有效时有效,并且 s 被借用,只要输出生命。这就是为什么删除word“修复”问题的原因:first_word 的结果被立即回收,因此借用立即结束,并且可以创建新的借用。
猜你喜欢
  • 2019-08-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多