我正在尝试将旧的编译器教科书中的翻译器/解析器示例从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
的工作原理。目的是在内部匹配中添加解析分支。不幸的是,这无法编译,因为我似乎无法理解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之后已经有一段时间了(并且从未付出过那么大的努力),而且这种性质的搜索结果似乎已经过时了。
答案 0 :(得分:1)
它与match
的返回值无关,甚至与match
本身的返回值无关::
use std::io::Read;
fn lexan() {
let mut input = std::io::stdin().bytes().peekable();
if let Some(&ch) = input.peek() {}
}
问题是您尝试绑定Peekable::peek
的结果,同时取消引用它(这是&
中的&ch
所做的)。在这种情况下,返回类型是Option<&Result<u8, std::io::Error>>
,因为Bytes
迭代器从基础流返回错误。由于此类型未实现Copy
,因此尝试取消引用该类型需要您转移该值的所有权。您不能这样做,因为您没有原始值 - 因此错误消息。
导致无法复制的部分是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
}