rustownershipclap

Method call on clap::App moving ownership more than once


Even after reading the chapters about reference ownership and borrowing, I cannot understand some things in the following code, effectively stopping me from calling more than one method from clap::App!

extern crate clap;

use clap::App;

fn main() {
    let mut app =
        App::new("name me").args_from_usage("<input_file>          'Sets the input file to use'");
    let matches = app.get_matches();
    app.print_help();
    println!(
        "Using input file: {}",
        matches.value_of("input_file").unwrap()
    );
}

Compiling this code leads to:

error[E0382]: use of moved value: `app`
 --> src/main.rs:9:5
  |
8 |     let matches = app.get_matches();
  |                   --- value moved here
9 |     app.print_help();
  |     ^^^ value used here after move
  |
  = note: move occurs because `app` has type `clap::App<'_, '_>`, which does not implement the `Copy` trait
  1. If I understand correctly, app.get_matches() asks to borrow the ownership, thus app must be mut. Where does the ownership go once the function returns?
  2. I thought app would still have ownership of the object, yet the compiler has a different opinion.

How can I get the matches, and effectively still call another method, such as print_help on app then?


Solution

  • Read the function signature for App::get_matches:

    fn get_matches(self) -> ArgMatches<'a>
    

    This takes self by value, also said as it consumes the value; you cannot call any methods on it afterwards. There's nothing to be done about this; presumably the author has good rationale for this.

    Now review App::print_help:

    fn print_help(&mut self) -> ClapResult<()>
    

    It takes a reference (which happens to be mutable). You do not have to transfer ownership to call this method.


    If I understand correctly, app.get_matches() asks to borrow the ownership, thus app must be mut. Where does the ownership go once the function returns?

    You do not understand correctly, in multiple dimensions.

    1. get_matches consumes the value, it does not borrow anything.
    2. A value does not need to be mutable to be borrowed.
    3. When you do borrow something, the ownership doesn't "go" anywhere. The original owner continues to own it. That's why it's called borrowing.

    How can I get the matches, and effectively still call another method, such as print_help on app then?

    You don't. The obvious workaround is to clone the original object, producing a second value. Then you can consume one value and still call methods on the second value.


    Basically, it sounds like you are trying to do something that the library is discouraging you from doing. Perhaps you should re-evaluate your goals and/or review the intended usage of the library. For example, get_matches will automatically display the help text when the user requests it, so why should your code try to do so?

    From the Clap issue tracker:

    You have a few options. You can either use AppSettings::ArgRequiredElseHelp or you can keep the move from happening by using App::get_matches_from_safe_borrow.