我正在尝试将旧编译器教科书中的翻译器/解析器示例从 C 移植到 Rust。
我有以下代码:
use std::io::Read;
fn lexan() {
let mut input = std::io::stdin().bytes().peekable();
loop {
match input.peek() {
Some(&ch) => {
match ch {
_ => println!("{:?}", input.next()),
}
}
None => break,
}
}
}
此时我并没有主动尝试解析输入,只是想了解 match
是如何工作的。目的是将解析分支添加到内部匹配中。不幸的是,这无法编译,因为我似乎无法理解匹配的语义:
error[E0507]: cannot move out of borrowed content
--> src/main.rs:7:18
|
7 | Some(&ch) => {
| ^--
| ||
| |hint: to prevent move, use `ref ch` or `ref mut ch`
| cannot move out of borrowed content
据我了解,这个错误是因为我不拥有match
的返回值。问题是,我不相信我正在使用任一匹配项的返回值。我认为 input.next()
可能是问题所在,但不管有没有这部分(或者实际上,整个 println! 调用)都会出现同样的错误。
我在这里错过了什么?自从我研究 Rust 以来已经有一段时间了(而且从来没有认真研究过),并且大多数针对这种性质的东西的搜索结果似乎已经过时了。
最佳答案
与match
的返回值无关,甚至 match
本身::
use std::io::Read;
fn lexan() {
let mut input = std::io::stdin().bytes().peekable();
if let Some(&ch) = input.peek() {}
}
问题是您正在尝试绑定(bind) Peekable::peek
的结果在取消引用时(这就是 &
中的 &ch
所做的)。在这种情况下,返回类型是 Option<&Result<u8, std::io::Error>>
因为Bytes
迭代器从底层流返回错误。由于此类型未实现 Copy
,尝试取消引用该类型需要您转移该值的所有权。您不能这样做,因为您不拥有原始值——因此会出现错误消息。
导致无法复制的那一 block 是Result
的错误类型.因此,您可以匹配更深一层:
match input.peek() {
Some(&Ok(ch)) => {
match ch {
_ => println!("{:?}", input.next()),
}
}
Some(&Err(_)) => panic!(),
None => break,
}
请注意,这段代码几乎无法编译。 peek
的结果next
时会失效被调用,所以对这段代码的如此多的小改动将触发借用检查器使代码失败。事实上,我有点惊讶上面的方法在第一次尝试时就起作用了。
如果你根本不关心错误,你可以这样做
while let Some(&Ok(ch)) = input.peek() {
match ch {
_ => println!("{:?}", input.next()),
}
}
不幸的是,您不能拆分中间部分,因为这会导致借用 input
。在通话期间持续 next
:
while let Some(x) = input.peek() {
match *x {
Ok(ch) => {
match ch {
_ => println!("{:?}", input.next()),
}
}
Err(_) => {}
}
// Could still use `x` here, compiler doesn't currently see that we don't
}
关于parsing - 使用 match 查看 stdin,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45177131/