Method call on clap::App moving ownership more than once
Asked Answered
E

2

6

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?

Electronic answered 3/12, 2016 at 19:18 Comment(0)
B
6

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.

Beuthen answered 3/12, 2016 at 19:30 Comment(5)
Thanks for shedding light on my big misunderstanding here! It's just a strange feeling on some point Rust, at first…Electronic
@Electronic yeah, there's definitely a learning curve, but pretty much everything has a good reason for existing. In this case, I wish I could explain exactly why this library is designed like this. The best I can provide is that clap::App documentation refers to itself as a builder. Generally, once you have built something, the builder is consumed in the process.Beuthen
@Beuthen nicely explained. May I add this: many command line tools show full help on a 'bare' command invocation, including java and cloc. So I see it as reasonable for @Electronic to want clap to provide a full help message. I have not yet found a simple way to provide this behavior with clap.Excogitate
@DavidJames certainly, although that sounds like a case for a feature request for clap itself. My point is mostly that clap has chosen to be opinionated in design, hopefully for a good reason. Going with the flow will make using a library easier. ^_^Beuthen
Re: "presumably the author has good rationale for this" ... I asked directly on the Clap issue tracker: github.com/kbknapp/clap-rs/issues/785Excogitate
R
0

I had to show the help in some situations and it was really a p*i*t*a™.

So, my last solution was:

let app = Command::new("app") ...
let matches = app.clone().get_matches();

...

let show_help = || {
    let mut app_mut = app.clone();
    let _ = app_mut.print_long_help();
};

...

Now I can show_help() whenever I want.

I'm not sure I'm doing the right thing, this seems bizarre, but it was the way I managed to solve it without pulling my hair out.

Revolver answered 28/6, 2023 at 22:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.