来自展开循环的可变借用冲突
Mutable borrow conflict from unrolled loop
考虑以下代码 (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
这绝对是胡说八道!该行与自身 冲突 等。我在这个错误中看到的唯一线索是循环正在展开。但是,循环中的所有借用不应该在每次迭代结束时到期吗?
以上代码的实际语义问题是什么,修复方法是什么?
在 Rust 中不可能引用同一结构中的某些东西。
想想看:
struct Line<'a> {
text: Box<String>,
column: &'a str,
}
'a
的目的是什么? text
字段的生命周期(顺便说一下,Box
环绕 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
:每个 Lines
实例具有相同的生命周期 。这意味着推断的生命周期必须大于循环的生命周期,因此循环的每次迭代确实使可变引用保持活动状态,因此该行实际上与自身(或者更确切地说,先前的迭代)冲突方法。循环没有展开——只是循环中的借用确实还活着。
考虑以下代码 (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
这绝对是胡说八道!该行与自身 冲突 等。我在这个错误中看到的唯一线索是循环正在展开。但是,循环中的所有借用不应该在每次迭代结束时到期吗?
以上代码的实际语义问题是什么,修复方法是什么?
在 Rust 中不可能引用同一结构中的某些东西。
想想看:
struct Line<'a> {
text: Box<String>,
column: &'a str,
}
'a
的目的是什么? text
字段的生命周期(顺便说一下,Box
环绕 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
:每个 Lines
实例具有相同的生命周期 。这意味着推断的生命周期必须大于循环的生命周期,因此循环的每次迭代确实使可变引用保持活动状态,因此该行实际上与自身(或者更确切地说,先前的迭代)冲突方法。循环没有展开——只是循环中的借用确实还活着。