Possible to use StructOpt or Clap parser to parse String?

I use StructOpt to parse my command line arguments and now I'm wondering if it's possible to use the constructed parser (by StructOpt or Clap) to parse a String into one of the structs that derives StructOpt.
What I want to do: I would like to parse a config file (not really command line arguments, so just running a command line parser on it wouldn't work) and most of it is very basic, so I do these using simple line splits and such, but I also would like to parse a line with structs into these structs. As StructOpt already parses Strings into structs, I was wondering if I could re-use that parser to parse this String.

I saw somebody using from_iter to parse Strings, but then I get an error

"error[E0599]: no variant or associated item named from_iter found for enum CodomainFunction in the current scope
--> src/codomain.rs:132:27
|
15 | pub enum CodomainFunction {
| ------------------------- variant or associated item from_iter not found here
...
132 | CodomainFunction::from_iter(codomain_function_string);
| ^^^^^^^^^ variant or associated item not found in CodomainFunction
|
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following trait defines an item from_iter, perhaps you need to implement it:
candidate #1: FromIterator"

Does anybody know how to do this by chance or have a pointer in the right direction? Thanks in advance.

Cheers,
Tobias

from_iter is a method of the StructOpt trait. Does your enum implement that trait, and have you imported the trait (use structopt::StructOpt;) in the module where you're calling the method?

Edit: Here's a short example program that works.

use structopt::StructOpt;

#[derive(StructOpt, PartialEq, Debug)]
enum Foo {
    A,
    B,
}

fn main() {
    let f = Foo::from_iter(vec!["foo", "a"]);
    assert_eq!(f, Foo::A)
}

Thanks for your quick response. Compiling your example program results in the same error (see below), and I have indeed derived the trait in my program as in your example. So, I'm guessing I'm doing something wrong here. To make this example work, I added

structopt = "0.1.0"
structopt-derive = "0.1.0"

to my Cargo.toml file and added

extern crate structopt;
#[macro_use]
extern crate structopt_derive;

to the top of src/main.rs, as otherwise I get an error that the derive macro StructOpt can't be found. I'm running the latest nightly btw.

The error and a warning that seems weird to me, as we are using it do a derivation:

warning: unused import: structopt::StructOpt
--> src/main.rs:5:5
|
5 | use structopt::StructOpt;
| ^^^^^^^^^^^^^^^^^^^^
|
= note: #[warn(unused_imports)] on by default

error[E0599]: no variant or associated item named from_iter found for enum Foo in the current scope
--> src/main.rs:14:18
|
8 | enum Foo {
| -------- variant or associated item from_iter not found here
...
14 | let f = Foo::from_iter(vec!["foo", "a"]);
| ^^^^^^^^^ variant or associated item not found in Foo
|
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following trait defines an item from_iter, perhaps you need to implement it:
candidate #1: FromIterator

from_iter requires structopt 0.2 or higher. The lastest version is 0.3.

Oh wow, that's stupid, I copied that without thinking from the crate page... It works now! Thanks a bunch and have a great day! :slight_smile:

Btw, do you perhaps know whether it is possible to just pass vec!["a"] and get Foo::A back, in your example?

Normally, clap/structopt ignore the first argument, because that's where the name of the executable goes. So you could pass something like vec!["", "a"] instead. (It doesn't matter what you put in the first argument.)

Or you can use the NoBinaryName setting:

use structopt::StructOpt;
use structopt::clap::AppSettings;

#[derive(StructOpt, PartialEq, Debug)]
#[structopt(setting(AppSettings::NoBinaryName))]
enum Foo {
    A,
    B,
}

fn main() {
    let f = Foo::from_iter(vec!["a"]);
    assert_eq!(f, Foo::A)
}

NoBinaryName will break the normal from_args method. If you use it, then you'll need to manually skip the first argument when parsing args from the command line:

let foo = Foo::from_iter(std::env::args_os().skip(1));

Ah, great to know! Cheers for the extensive answer. In my case, I want to keep the regular command line argument parsing untouched, so I'll use your trick of just inserting something in the vector instead.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.