BufReader does not implement Copy error in a loop

I am trying to run

for line in buffer_reader.lines() { .. }

within another for loop, and I get the "BufReader does not implement Copy" error. I get what's wrong, but not what to do about it. Apparently the first iteration of my loop moves the buffer_reader, and in the next iteration it can't be moved again. But, how can I tell it not to move? Do I have to implement the Copy trait on std::io::BufReader? I imagine there's a much easier way.

Usually rustc suggest a borrow somewhere when I run into ownership issues, but this time I'm stumped.

I'm guessing you are using break to stop the loop in the middle? In that case, you can do this:

for line in (&mut buffer_reader).lines() { ... }

By passing a mutable reference, the lines function will not consume the BufReader. This works because the BufRead trait is implemented on mutable references.

Another option is to write your loop using read_line, like this:

let mut line = String::new();
while buffer_reader.read_line(&mut line)? > 0 {
    ...
    line.clear();
}

No, this is never the answer unless the struct is your own custom struct that only contains simple fields like integers.

The real error is that you're destroying an object when you didn't want to destroy it. The compiler mentions Copy because the way you're destroying the object wouldn't destroy a value that is Copy. The fix is to fix the underlying issue: change your code to not destroy the value.

2 Likes

Hmm. I wasn't aware you could put parenthesis around an expression in that way. I tried with a '&' in different ways, as I figured I needed to make it a reference. I kind of knew what was going on, but couldn't figure out the syntax.

Nice alternative solution! I was thinking of using read_line, but got stuck on the idea that it appended to a buffer. Using it in a while loop like that didn't occur to me either.

And, yeah I was 99% certain implementing Copy was very, very wrong... :sweat_smile:

Now I got past that compiler error, I just need to figure out why the rest of my program doesn't work as intended, but that's quite likely a problem with my algorithm.

Thanks!

Generally, the ampersand has a pretty low precedence, so stuff like &mut reader.lines() is parsed as &mut (reader.lines()) rather than (&mut reader).lines().

1 Like

Ok, that was good to know. Is there a simple list somewhere of the precedence rules? I did look at the full language reference, and I think it was a bit too much for me to parse at this time.

I don't know of a list.

Here.

5 Likes

Thanks!

Why couldn't you? Rust's grammar is very uniform. You can combine expressions in basically arbitrary ways. Some combinations are very common, and others are so ugly and non-idiomatic that you basically never see them in production code, but it doesn't mean they are syntactically inexpressible.

The syntax for method calls is not variable.method(…), it's <any expression>.method(…). In general, a parser for a programming language is the easiest to implement if expressions are allowed to be fully general and to form a tree with arbitrary nesting; and apart from a very small set of technically necessary exceptions (eg. no struct literals in the condition of an if expression), Rust does work that way. The designers of the grammar didn't want to intentionally restrict the set of syntactically parseable expressions – that would only make the lives of everyone harder unnecessarily.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.