Search code examples
rustcompiler-warningsfalse-positive

rustc false positive warning about value never read?


Following this article about writing a shell in Rust. Compiler outputs a warning about a variable never being read.

use std::io::stdin;
use std::io::stdout;
use std::io::Write;
use std::process::Command;
use std::path::Path;

 fn main(){
    let mut input = String::new();

    loop {
            print!("> ");
            stdout().flush().unwrap();
//              input = String::from("");  //  **<===== HERE**
            stdin().read_line(&mut input).unwrap();
            let mut parts = input.trim().split_whitespace();
            let command = parts.next().unwrap();
            let args = parts;
            match command {
                "cd" => {
                    let new_dir = args.peekable().peek().map_or("/", |x| *x);
                    let root = Path::new(new_dir);
                    if let Err(e) = std::env::set_current_dir(&root) {
                        eprintln!("{}", e);
                    }
                },
                "exit" => return,
                command => {
                    let child = Command::new(command)
                        .args(args)
                        .spawn();
                    // gracefully handle malformed user input
                    match child {
                        Ok(mut child) => { child.wait().unwrap(); },
                        Err(e) => eprintln!("{}", e),
                    };
               }
           }
    }
}

However, commenting out this line causes program to bug: here is the behavior before and after commenting:

usn@DESKTOP:~/bqy/rust/p2$ cargo run
warning: value assigned to `input` is never read
 --> src/main.rs:8:10
  |
8 |     let mut input = String::new();
  |             ^^^^^
  |
  = note: `#[warn(unused_assignments)]` on by default
  = help: maybe it is overwritten before being read?

    Finished dev [unoptimized + debuginfo] target(s) in 0.02s
     Running `target/debug/p2`
> ls
Cargo.lock  Cargo.toml  src  target
> ls
Cargo.lock  Cargo.toml  src  target
> exit
usn@DESKTOP:~/bqy/rust/p2$ vi src/main.rs
usn@DESKTOP:~/bqy/rust/p2$ cargo run
   Compiling p2 v0.1.0 (/mnt/d/MMM/projects/bqy/rust/p2)
    Finished dev [unoptimized + debuginfo] target(s) in 1.13s
     Running `target/debug/p2`
> ls
Cargo.lock  Cargo.toml  src  target
> ls
ls: cannot access 'ls': No such file or directory
> exit
ls: cannot access 'ls': No such file or directory
ls: cannot access 'exit': No such file or directory
> ^C
usn@DESKTOP:~/bqy/rust/p2$ vi src/main.rs

Simple explanation of unwanted behavior is that command line is not resetted. So, why does the compiler complains ?

Thank you for reading.


Solution

  • Without the line to clear the buffer, its content is reused from one iteration to another. This is why your program doesn't work without

    input = String::from("");
    

    But this gives you a warning because you gave input a value when you declared it:

    let mut input = String::new();
    //           ^^^^^^^^^^^^^^^^
    

    and this value is not used, since literally the first use of input is to override it. So just don't give it a value:

    let mut input;
    

    In Rust this is perfectly safe and the compiler won't let you accidentally use input before you initialize it.


    Alternatively, if you goal was to reuse the buffer to save on memory, you should use

    input.clear();
    

    because input = String::from(""); creates a completely new string with a new buffer and throws the other one away.