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

Multi tool use
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.

S qG fzUh0 1clcQ7CVHRF47Sabw,uCD
O zwmpilkuVTcugD 1 dkrWvo7R7rllCK5g7VYzsZ3UsJemlKmXE0B,Lxcduag7KG,n

Popular posts from this blog

PHP contact form sending but not receiving emails

Do graphics cards have individual ID by which single devices can be distinguished?

Create weekly swift ios local notifications