考虑下面的代码(Playpen),它只是简单地解析来自stdin的输入,并将每一行和对该行的引用放在一个结构中:
use std::io;
use std::io::BufRead;
struct Line<'a> {
text: Box<String>,
column: &'a str,
}
fn main() {
let column = 1;
let stdin = io::stdin();
let mut lines: Vec<Line> = Vec::new();
for line_res in stdin.lock().lines() {
lines.push(Line {
text: Box::new(line_res.unwrap()),
column: "",
});
let line = lines.last_mut().unwrap();
line.column = line.text.split_whitespace().nth(column)
.unwrap_or("");
}
}
也就是说,Line::column
应该引用Line::text
。请注意,我最初将column
设置为""
(稍后进行修改),因为我不知道在创建时引用text
元素的方法。
不幸的是,上面的代码没有编译,吐出以下非常钝的错误消息:
<anon>:15:3: 15:8 error: cannot borrow `lines` as mutable more than once at a time
<anon>:15 lines.push(Line {
^~~~~
note: in expansion of for loop expansion
<anon>:14:2: 23:3 note: expansion site
<anon>:20:14: 20:19 note: previous borrow of `lines` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `lines` until the borrow ends
<anon>:20 let line = lines.last_mut().unwrap();
^~~~~
note: in expansion of for loop expansion
<anon>:14:2: 23:3 note: expansion site
<anon>:24:2: 24:2 note: previous borrow ends here
<anon>:9 fn main() {
...
<anon>:24 }
^
<anon>:20:14: 20:19 error: cannot borrow `lines` as mutable more than once at a time
<anon>:20 let line = lines.last_mut().unwrap();
^~~~~
note: in expansion of for loop expansion
<anon>:14:2: 23:3 note: expansion site
<anon>:20:14: 20:19 note: previous borrow of `lines` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `lines` until the borrow ends
<anon>:20 let line = lines.last_mut().unwrap();
^~~~~
note: in expansion of for loop expansion
<anon>:14:2: 23:3 note: expansion site
<anon>:24:2: 24:2 note: previous borrow ends here
<anon>:9 fn main() {
...
<anon>:24 }
^
<anon>:20:14: 20:19 error: cannot borrow `lines` as mutable more than once at a time
<anon>:20 let line = lines.last_mut().unwrap();
^~~~~
note: in expansion of for loop expansion
<anon>:14:2: 23:3 note: expansion site
<anon>:20:14: 20:19 note: previous borrow of `lines` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `lines` until the borrow ends
<anon>:20 let line = lines.last_mut().unwrap();
^~~~~
note: in expansion of for loop expansion
<anon>:14:2: 23:3 note: expansion site
<anon>:24:2: 24:2 note: previous borrow ends here
<anon>:9 fn main() {
...
<anon>:24 }
^
error: aborting due to 3 previous errors
当然这是胡说八道!除其他事项外,该行与本身冲突。我在这个错误中可以看到的唯一线索是循环正在展开的事实。但是,在循环中所做的所有借用都不应该在每次迭代结束时到期吗?
上述代码的实际语义问题是什么,修复是什么?
答案 0 :(得分:4)
Rust中不可能引用同一结构中的某些内容。
想一想:
struct Line<'a> {
text: Box<String>,
column: &'a str,
}
'a
的目的是什么? text
字段的生命周期(顺便说一句,围绕Box
的{{1}}包裹是完全多余的。因此,在它已经存在之前,你不能表达它。
如果允许这样的 ,你就会遇到这样的问题:
String
当两个值存储在一起时,没有办法解决这个问题;它们必须分开存放。最有可能适用于您的情况的解决方法是存储索引,例如开始和结束索引为let mut line = Line { text: "foo".to_owned(), column: "" };
line.column = &self.text;
line.text = "bar".to_owned();
// Uh oh, column is now invalid, pointing to freed memory
。
现在:为什么会出现这些特殊错误?归结为(usize, usize)
被推断为;您的行向量为'a
一生Vec<Lines<'x>>
:每个'x
实例具有相同的生命周期。这意味着推断的生命周期必须大于循环的生命周期,因此循环的每次迭代确实使可变引用保持活着,因此该行实际上与其自身(或者更确切地说,先前的迭代)冲突办法。循环没有展开 - 它只是循环的借用确实还活着。