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

时间:2018-12-28 05:29:14

标签: rust ownership borrowing

我正在从The Rust Programming Language book available from No Starch Press学习Rust,但是遇到了一个问题,即编译器的行为与第4章第4章中的书中所解释的不一样。 77。

该书的第4章正在讨论所有权,第p页的示例。 77与此类似,但在var user_profile =[ { "assessmentType":"FINAL", "assessCatId":-1, "assessReason":"2", "assessAmount":"", "assessTotal":null }, { "assessmentType":"FINAL", "assessCatId":-1, "assessReason":"2", "assessTotal":null }, { "assessmentType":"FINAL", "assessCatId":-1, "assessReason":"", "assessTotal":null }, { "assessmentType":"FINAL", "assessCatId":0, "assessReason":null, "assessAmount":"", "assessPenalty":"", "assessTotal":0 }, { "assessmentType":"FINAL", "assessCatId":0, "assessReason":null, "assessTotal":null }, { "assessmentType":"FINAL", "assessCatId":0, "assessReason":"", "assessTotal":null }, { "assessmentType":"FINAL", "assessCatId":0, "assessReason":"", "assessTotal":null }, { "assessmentType":"FINAL", "assessCatId":0, "assessReason":"2075-09-09", "assessAmount":"2075-09-17", "assessTotal":null }, { "assessmentType":"FINAL", "assessCatId":0, "assessReason":"2075-09-09", "assessTotal":null }, { "assessmentType":"FINAL", "assessCatId":0, "assessReason":"2075-09-17", "assessTotal":null }, { "assessmentType":"FINAL", "assessCatId":1, "assessReason":"", "assessAmount":"0", "assessPenalty":"0", "assessTotal":0 }, { "assessmentType":"FINAL", "assessCatId":2, "assessReason":"", "assessAmount":"0", "assessPenalty":"0", "assessTotal":0 }, { "assessmentType":"FINAL", "assessCatId":3, "assessReason":"", "assessAmount":"0", "assessPenalty":"0", "assessTotal":0 }, { "assessmentType":"FINAL", "assessCatId":1, "assessReason":"A", "assessAmount":"1", "assessPenalty":"2", "assessTotal":3 }, { "assessmentType":"FINAL", "assessCatId":2, "assessReason":"B", "assessAmount":"3", "assessPenalty":"4", "assessTotal":7 }, { "assessmentType":"FINAL", "assessCatId":3, "assessReason":"C", "assessAmount":"5", "assessPenalty":"6", "assessTotal":11 } ] const output = user_profile.filter(({ assessCatId,assessReason }) => (assessCatId >= 1 && assessCatId <= 3) && assessReason); console.log("here the outpuit is"); console.log(output);中没有最后的println!()(我也从第76页添加了注释和功能来创建MCVE)。 I also created a playground

main()

我了解为什么编译器在当前位置会引发错误。但是我从书中了解到,当我尝试清除字符串时,它应该引起了编译器错误,因为我无法借用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[..] } 可变,因为它也借来不可变,因此消除了我收到错误的可能性(即,即使没有最后的s,也不应编译)。但是,只要我不尝试在println!()操作之后使用对word的引用,它对我来说编译就很好。

该书使用的是Rust 1.21.0(请参阅第2页),而我使用的是Rust 1.31.0,因此这很可能是已引入编译器的更改,但我试图了解为什么。为什么现在比在书中指出会出错的地方更好地出错呢?

为清楚起见,我自己理解错误。我试图理解为什么它没有在书中所述的位置抛出编译器错误(即,为什么更改编译器行为?)。

1 个答案:

答案 0 :(得分:5)

这是non-lexical lifetimes所做的更改,{{3}}是Rust最新版本的更新(如果我没记错的话,请参见Rust 1.31引入的2018版稳定)。

在Rust的早期版本(包括本书所基于的版本)中,任何引用都应该在创建它的整个范围内都有效(也就是说,直到括号括起来)。如果您使用word删除了该行并尝试在旧版本上编译代码,则会产生相同的错误-“借来的是可变的,借来的是不可变的”。

现在,借阅检查器将跟踪引用是否真正被使用。如果您在word之后没有使用s.clear(),则可以假设在s变成可变变量之前,可以安全地删除对s.clear()的不变引用,因此您已经提到过,此代码将被安全地编译。在println!处,借位检查器会看到不可变和可变借位的作用域是相交的,并确切地告诉您—请注意,错误分为三部分:

  1. 一成不变的借贷开始,
  2. 开始可变借贷
  3. 不可变借贷的用途。