BufReader: move after for-loop with bufreader.lines()

Multi tool use
BufReader: move after for-loop with bufreader.lines()
I'm trying to read some lines from a file, skipping the first few and printing the rest, but I keep getting errors about used value after move:
use std::fs::File;
use std::io::{self, BufRead, BufReader, Read};
use std::path::Path;
fn skip_and_print_file(skip: &usize, path: &Path) {
let mut skip: usize = *skip;
if let Ok(file) = File::open(path) {
let mut buffer = BufReader::new(file);
for (index, line) in buffer.lines().enumerate() {
if index >= skip {
break;
}
}
print_to_stdout(&mut buffer);
}
}
fn print_to_stdout(mut input: &mut Read) {
let mut stdout = io::stdout();
io::copy(&mut input, &mut stdout);
}
fn main() {}
This is the error I'm getting:
error[E0382]: use of moved value: `buffer`
--> src/main.rs:15:30
|
10 | for (index, line) in buffer.lines().enumerate() {
| ------ value moved here
...
15 | print_to_stdout(&mut buffer);
| ^^^^^^ value used here after move
|
= note: move occurs because `buffer` has type `std::io::BufReader<std::fs::File>`, which does not implement the `Copy` trait
2 Answers
2
In order to avoid the move, use the Read::by_ref()
method. That way, you only borrow the BufReader
:
Read::by_ref()
BufReader
for (index, line) in buffer.by_ref().lines().enumerate() { ... }
// ^^^^^^^^^
// you can still use `buffer` here
As Lukas Kalbertodt says, use Read::by_ref
.
Read::by_ref
This prevents lines
from consuming the BufReader
and instead it consumes a &mut BufReader
. The same logic applies to iterators.
lines
BufReader
&mut BufReader
Instead of implementing skip
yourself, you can just use Iterator::take
. This has to be driven to completion with something like Iterator::count
though:
skip
Iterator::take
Iterator::count
use std::{
fs::File,
io::{self, BufRead, BufReader, Read},
path::Path,
};
fn skip_and_print_file(skip: usize, path: &Path) {
if let Ok(file) = File::open(path) {
let mut buffer = BufReader::new(file);
for _ in buffer.by_ref().lines().take(skip) {}
// Or: buffer.by_ref().lines().take(skip).for_each(drop);
print_to_stdout(&mut buffer);
}
}
fn print_to_stdout(mut input: &mut Read) {
let mut stdout = io::stdout();
io::copy(&mut input, &mut stdout).expect("Unable to copy");
}
fn main() {
skip_and_print_file(2, Path::new("/etc/hosts"));
}
Note that there's no reason to make the skip
variable mutable or even to pass in a reference. You can also take in AsRef<Path>
and then callers of skip_and_print_file
can just pass in a string literal.
skip
AsRef<Path>
skip_and_print_file
By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.