How to fix use of moved value error

I have a build error and tried some suggestions online but they did not work, I am trying to add a progress bar to my code, the code works perfectly well without the progress bar. Any help please ?

use std::fs::File;
use indicatif::{ProgressBar, ProgressStyle};
use std::io::{BufRead, BufReader, Write};
use bip39::Mnemonic;

fn main() {
    let input_file = File::open("input.txt").expect("Failed to open input file");
    let reader = BufReader::new(input_file);

    let output_file = File::create("output.txt").expect("Failed to create output file");
    let mut writer = std::io::BufWriter::new(output_file);

    let num_lines = reader.lines().count();
    let pb = ProgressBar::new(num_lines as u64);
    pb.set_style(ProgressStyle::default_bar()
        .template("[{elapsed_precise}] {bar:100.cyan/blue} {pos}/{len} ({percent}%)").expect("Failed to create progress bar")
        .progress_chars("##-"));

    for line in reader.lines() {
        if let Ok(mnemonic_str) = line {
            let valid = Mnemonic::parse_normalized(&mnemonic_str);
            
            if valid.is_ok() {
                writeln!(writer, "{}", mnemonic_str).expect("Failed to write to output file");
            }
            pb.inc(1);
        }
    }
    pb.finish_with_message("Validation completed");

    println!("Valid ones have been written to output.txt");
}

The error I get

error[E0382]: use of moved value: `reader`
  --> src\main.rs:19:17
   |
8  |     let reader = BufReader::new(input_file);
   |         ------ move occurs because `reader` has type `BufReader<File>`, which does not implement the `Copy` trait
...
13 |     let num_lines = reader.lines().count();
   |                            ------- `reader` moved due to this method call
...
19 |     for line in reader.lines() {
   |                 ^^^^^^ value used here after move
   |
note: `lines` takes ownership of the receiver `self`, which moves `reader`
  --> /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6\library\std\src\io\mod.rs:2554:14

For more information about this error, try `rustc --explain E0382`.
error: could not compile `project` (bin "project") due to 1 previous error

On mobile, but I think this should work: Rust Playground

I still got the error

warning: variable does not need to be mutable
  --> src\main.rs:13:9
   |
13 |     let mut lines = reader.lines();
   |         ----^^^^^
   |         |
   |         help: remove this `mut`
   |
   = note: `#[warn(unused_mut)]` on by default

error[E0382]: use of moved value: `lines`
  --> src\main.rs:20:17
   |
13 |     let mut lines = reader.lines();
   |         --------- move occurs because `lines` has type `std::io::Lines<BufReader<File>>`, which does not implement the `Copy` trait
14 |     let num_lines = lines.count();
   |                           ------- `lines` moved due to this method call
...
20 |     for line in lines {
   |                 ^^^^^ value used here after move
   |
note: `count` takes ownership of the receiver `self`, which moves `lines`
  --> /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6\library\core\src\iter\traits\iterator.rs:229:14

Note that this will have to read the whole file, which is probably not what you want.

I would use std::fs::metadata (or the unstable Seek::stream_len) to know the length in bytes of the file and then increment the progress bar by the number of bytes in line (note though this is slightly inaccurate since newline characters won't be counted).

If you insist in reading the whole file to know the number of lines you can use reader.by_ref().lines().count() instead of reader.lines().count(), which won't consume reader. Remember to reset reader by using Seek::unwind, or when you do reader.lines() for the second time it read nothing.

1 Like

Thanks for the help but I think i would leave out the progress bar, i was hoping it would be an easy something like 'tqdm' in python

Could you explain a bit how you would do this with tqdm? Maybe we could help achieve the same result easier than it seems to be.

tqdm also doesn't properly show a progress bar if the iterator length is not known ahead of time, like it happens for an iterator of file lines.

For example this is the normal output of tqdm on an iterator with a known length (I've showed all the lines and also added some delay so that none is skipped):

  0%|                                               | 0/7 [00:00<?, ?it/s]
 14%|█████▌                                 | 1/7 [00:01<00:06,  1.00s/it]
 29%|███████████                            | 2/7 [00:02<00:05,  1.01s/it]
 43%|████████████████                       | 3/7 [00:03<00:04,  1.01s/it]
 57%|██████████████████████                 | 4/7 [00:04<00:03,  1.01s/it]
 71%|███████████████████████████            | 5/7 [00:05<00:02,  1.01s/it]
 86%|█████████████████████████████████      | 6/7 [00:06<00:01,  1.01s/it]
100%|███████████████████████████████████████| 7/7 [00:07<00:00,  1.01s/it]

This is the output when the iterator has no known length, notice how there's no progress bar. To keep the example on topic I used an iterator over file lines, just like you were trying to do in your rust code:

0it [00:00, ?it/s]
1it [00:01,  1.01s/it]
2it [00:02,  1.01s/it]
3it [00:03,  1.01s/it]
4it [00:04,  1.01s/it]
5it [00:05,  1.01s/it]
6it [00:06,  1.01s/it]
7it [00:07,  1.01s/it]

tqdm has exactly the same problem as your rust code, except it doesn't tell you until you run it and see the problem for yourself.

@jofas , @SkiFire13 .... Thank you all for your help, i found a fix.
I read the lines again on top of the for-loop and defined reader again and it worked like a charm.
I will update my code in a moment.

@Cerber-Ursi thank you too for your help.

This is the modified code

use std::fs::File;
use indicatif::{ProgressBar, ProgressStyle};
use std::io::{BufRead, BufReader, Write};
use bip39::Mnemonic;

fn main() {
    let input_file = File::open("gain1.txt").expect("Failed to open input file");
    let reader = BufReader::new(input_file);

    let output_file = File::create("checksum.txt").expect("Failed to create output file");
    let mut writer = std::io::BufWriter::new(output_file);
	
    let num_lines = reader.lines().count();
    let pb = ProgressBar::new(num_lines as u64);
    pb.set_style(ProgressStyle::default_bar()
        .template("[{elapsed_precise}] {bar:100.cyan/blue} {pos}/{len} ({percent}%)").expect("Failed to create progress bar")
        .progress_chars("##-"));
		
	let input_file = File::open("gain1.txt").expect("Failed to open input file");
	let reader = BufReader::new(input_file);

    for line in reader.lines() {
        if let Ok(mnemonic_str) = line {
            let valid = Mnemonic::parse_normalized(&mnemonic_str);
            
            if valid.is_ok() {
                writeln!(writer, "{}", mnemonic_str).expect("Failed to write to output file");
            }
            pb.inc(1);
        }
    }
    pb.finish_with_message("Validation completed");

    println!("Valid ones have been written to output.txt");
}

I found out that the progress bar slowed down my code, without the progress bar it took 3 minutes to iterate over a file, with the progress bar, it took 3 minutes 30 seconds to iterate over the same file.