当范围内仍然存在不可变借用字符串切片引用时,为什么编译器不会在此可变借用上出错?

2023-12-09

我正在学习 RustRust 编程语言本书可从 No Starch Press 购买但遇到了一个问题,编译器的行为与书中第 4 章第 4 页中所解释的不同。 77.

本书的第 4 章讨论了所有权,以及第 4 页的示例。 77 与此类似,没有最后的println!() in main()(我还添加了第 76 页中的注释和函数来创建 MCVE)。我还创建了一个游乐场.

fn main() {
    let mut s = String::from("Hello world!");
    let word = first_word(&s);

    // according to book, compiler should not allow this mutable borrow
    // since I'm already borrowing as immutable, but it does allow it
    s.clear();

    // but of course I do get error here about immutable borrow later being
    // used here, but shouldn't it have errored on the clear() operation before
    // it got here?
    println!("First word of s is \"{}\"", word);
}

// return string slice reference to first word in string or entire string if
// no space found
fn first_word(s: &String) -> &str {
    let bytes = s.as_bytes();

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

    &s[..]
}

我明白为什么编译器会在当前的位置抛出错误。但我从书中的理解是should当我尝试清除字符串时导致编译器错误,因为我无法借用s是可变的,因为它也被借用为不可变的,从而消除了我收到的错误的可能性(即,它不应该编译即使没有我的决赛println!())。但只要我不尝试使用引用,它对我来说编译得很好word之后clear()手术。

本书使用 Rust 1.21.0 (seep。 2) 而我使用的是 Rust 1.31.0——所以这可能是编译器引入的一个变化,但我试图理解why。为什么像现在这样犯错误比书中说会犯错误更好?

需要明确的是,我理解这些错误本身。我试图理解为什么它不会在书中所说的位置抛出编译器错误(即为什么编译器行为发生变化?)。


这是由于以下原因而发生的变化非词汇生命周期,最新版本 Rust 中所做的更新(如果我没记错的话,在 Rust 1.31 中引入的 2018 版本中已稳定)。

在 Rust 的早期版本(包括本书所基于的版本)中,任何引用都应该在其创建的整个范围内都有效(即,直到大括号末尾)。如果您使用删除该行word并尝试在旧版本上编译代码,它会发出相同的错误 - “借用为可变,而借用为不可变”。

现在,借用检查器跟踪该引用是否被真正使用。如果你没有使用word after s.clear(),假设对的不可变引用s可以在之前安全地丢弃s.clear()采用可变的,因此,正如您所提到的,该代码将被安全地编译。当。。。的时候println!在那里,借用检查器会看到不可变和可变借用的作用域是相交的,并准确地告诉您这一点 - 请注意,错误分为三个部分:

  1. 不可变借用的开始,
  2. 可变借用的开始,
  3. 不可变借用的使用。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

当范围内仍然存在不可变借用字符串切片引用时,为什么编译器不会在此可变借用上出错? 的相关文章

随机推荐