Reputation: 83
I'm trying to port a translator/parser example from an old compiler textbook from C into Rust.
I have the following code:
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,
}
}
}
At this point I'm not actively trying to parse the input, just get my head around how match
works. The aim is to add parse branches to the inner match. Unfortunately this fails to compile because I appear to fail in understanding the semantics of 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
From what I understand, this error is because I don't own the return value of the match
. The thing is, I don't believe that I'm using the return value of either match. I thought perhaps input.next()
may have been the issue, but the same error occurs with or without this part (or indeed, the entire println! call).
What am I missing here? It's been some time since I looked at Rust (and never in a serious level of effort), and most of the search results for things of this nature appear to be out of date.
Upvotes: 1
Views: 649
Reputation: 431789
It's got nothing to do with the return value of match
, or even match
itself::
use std::io::Read;
fn lexan() {
let mut input = std::io::stdin().bytes().peekable();
if let Some(&ch) = input.peek() {}
}
The issue is that you are attempting to bind the result of Peekable::peek
while dereferencing it (that's what the &
in &ch
does). In this case, the return type is an Option<&Result<u8, std::io::Error>>
because the Bytes
iterator returns errors from the underlying stream. Since this type does not implement Copy
, trying to dereference the type requires that you transfer ownership of the value. You cannot do so as you don't own the original value — thus the error message.
The piece that causes the inability to copy is the error type of the Result
. Because of that, you can match one level deeper:
match input.peek() {
Some(&Ok(ch)) => {
match ch {
_ => println!("{:?}", input.next()),
}
}
Some(&Err(_)) => panic!(),
None => break,
}
Be aware that this code is pretty close to being uncompilable though. The result of peek
will be invalidated when next
is called, so many small changes to this code will trigger the borrow checker to fail the code. I'm actually a bit surprised the above worked on the first go.
If you didn't care about errors at all, you could do
while let Some(&Ok(ch)) = input.peek() {
match ch {
_ => println!("{:?}", input.next()),
}
}
Unfortunately, you can't split the middle, as this would cause the borrow of input
to last during the call to 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
}
Upvotes: 1