我从 Rust 借用检查器那里得到了一个编译错误,但我不明白为什么会出错。可能是我没有完全理解生命周期方面的知识。
我已将其简化为一个短小的代码示例。在主函数中,我想要执行以下操作:
fn main() {
let codeToScan = "40 + 2";
let mut scanner = Scanner::new(codeToScan);
let first_token = scanner.consume_till(|c| { ! c.is_digit ()});
println!("first token is: {}", first_token);
// scanner.consume_till(|c| { c.is_whitespace ()}); // WHY DOES THIS LINE FAIL?
}
尝试第二次调用scanner.consume_till
会导致如下错误:example.rs:64:5: 64:12 error: cannot borrow `scanner` as mutable more than once at a time
example.rs:64 scanner.consume_till(|c| { c.is_whitespace ()}); // WHY DOES THIS LINE FAIL?
^~~~~~~
example.rs:62:23: 62:30 note: previous borrow of `scanner` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `scanner` until the borrow ends
example.rs:62 let first_token = scanner.consume_till(|c| { ! c.is_digit ()});
^~~~~~~
example.rs:65:2: 65:2 note: previous borrow ends here
example.rs:59 fn main() {
...
example.rs:65 }
基本上,我创建了类似于自己的迭代器,并且相当于“next”方法需要使用&mut self
。因此,在同一作用域中不能多次使用该方法。
但是,Rust标准库有一个迭代器可以在同一作用域中使用多次,并且它也需要一个&mut self
参数。
let test = "this is a string";
let mut iterator = test.chars();
iterator.next();
iterator.next(); // This is PERFECTLY LEGAL
为什么 Rust 标准库的代码能编译,而我的不能?(我确定生命周期注释是问题的根源,但我的生命期理解并没有让我预料到会出现问题。)
这是我的完整代码(只有 60 行,为了这个问题缩短了):
use std::str::{Chars};
use std::iter::{Enumerate};
#[deriving(Show)]
struct ConsumeResult<'lt> {
value: &'lt str,
startIndex: uint,
endIndex: uint,
}
struct Scanner<'lt> {
code: &'lt str,
char_iterator: Enumerate<Chars<'lt>>,
isEof: bool,
}
impl<'lt> Scanner<'lt> {
fn new<'lt>(code: &'lt str) -> Scanner<'lt> {
Scanner{code: code, char_iterator: code.chars().enumerate(), isEof: false}
}
fn assert_not_eof<'lt>(&'lt self) {
if self.isEof {fail!("Scanner is at EOF."); }
}
fn next(&mut self) -> Option<(uint, char)> {
self.assert_not_eof();
let result = self.char_iterator.next();
if result == None { self.isEof = true; }
return result;
}
fn consume_till<'lt>(&'lt mut self, quit: |char| -> bool) -> ConsumeResult<'lt> {
self.assert_not_eof();
let mut startIndex: Option<uint> = None;
let mut endIndex: Option<uint> = None;
loop {
let should_quit = match self.next() {
None => {
endIndex = Some(endIndex.unwrap() + 1);
true
},
Some((i, ch)) => {
if startIndex == None { startIndex = Some(i);}
endIndex = Some(i);
quit (ch)
}
};
if should_quit {
return ConsumeResult{ value: self.code.slice(startIndex.unwrap(), endIndex.unwrap()),
startIndex:startIndex.unwrap(), endIndex: endIndex.unwrap() };
}
}
}
}
fn main() {
let codeToScan = "40 + 2";
let mut scanner = Scanner::new(codeToScan);
let first_token = scanner.consume_till(|c| { ! c.is_digit ()});
println!("first token is: {}", first_token);
// scanner.consume_till(|c| { c.is_whitespace ()}); // WHY DOES THIS LINE FAIL?
}
&self
或&mut self
参数上的生命周期注释实际上可以使借用更长寿;(5)甚至是什么决定了&self
或&mut self
参数的借用长度?现在深入编译器源码是唯一的方法吗? - Charlie Flowersself
在创建借用的范围内(或最近的封闭语句,如果它不是立即分配给一个变量)中被借用(更容易将其视为“借用持续的时间与保留返回值的时间一样长”)。 - huonself
(即它说你不能返回对局部变量的引用)。第二部分不太准确,正如你所说。(第一部分忽略了事实,即你可以通过static X: Foo = ...; &X
返回一个&'static Foo
。) - huon&
引用之间没有连接,则借用只是该表达式:“x.takes_mut_self() == x.takes_mut_self()" 是可以的(如果函数返回,例如uint
),尽管在单个语句中可变地“borrowing” 了x
两次。如果有引用,借用将人为地延长到语句中(因为替代方案非常麻烦:需要很多临时变量)。 - huon