Dan*_*Dan 5 ownership rust borrowing
我正在从No Starch Press的《 Rust编程语言》一书中学习Rust,但是遇到了一个问题,即编译器的行为与第4页第4章中的解释不符。77。
本书的第4章正在讨论所有权,第p页的示例。77与此类似,但是没有最后的println!()输入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[..]
}
Run Code Online (Sandbox Code Playgroud)
我理解为什么编译器在当前位置会引发错误。但是我从书中了解到,当我尝试清除字符串时,它应该导致编译器错误,因为我不能借来s可变,因为它也被借为不可变的,从而消除了我收到错误的可能性(即,应该即使没有我的final 也无法编译println!())。但是,只要我不尝试word在clear()操作后使用引用,它对我来说编译就很好。
该书使用的是Rust 1.21.0(请参阅第2页),而我使用的是Rust 1.31.0,因此这很可能是已引入编译器的更改,但我试图理解为什么。为什么现在比在书中指出会出错的地方更好地出错呢?
明确地说,我理解错误本身。我试图理解为什么它不会在书中所述的位置抛出编译器错误(即,为什么要更改编译器行为?)。
这是由于非词条生存期而导致的更改,该生存期是Rust的最新版本中的更新(如果我没有记错的话,请在Rust 1.31引入的2018版中进行稳定化)。
在Rust的早期版本(包括该书所基于的版本)中,任何引用都应该在创建它的整个范围内都有效(也就是说,直到括号括起来)。如果您使用删除了该行word并尝试在旧版本上编译代码,则会产生相同的错误-“借来的是可变的,借来的是不可变的”。
现在,借阅检查器将跟踪引用是否真正被使用。如果您不使用wordafter s.clear(),则假定s可以安全地删除对unmutable的引用,然后再s.clear()进行可变变量的引用,因此,正如您已经提到的,此代码将被安全地编译。当println!存在时,借位检查器会看到不可变且可变的借位的范围是相交的,并确切地告诉您—请注意,错误分为三个部分: