Loading pageā¦
Rust walkthroughs
Loading pageā¦
clap::ArgMatches::get_many differ from get_one for handling multiple argument values?get_one retrieves a single value for an argument, returning Option<&T>, while get_many retrieves all values for an argument that accepts multiples, returning Option<Iter<T>>. The key difference is that get_one returns the last value when multiple values exist (or only value), whereas get_many iterates over all provided values. Use get_one for arguments that logically accept one value (like --config file.toml) and get_many for arguments where users provide multiple values (like --include a.txt --include b.txt). Both methods require the argument to have been defined with takes_value(true) or similar, and both are generic over the return type, parsing values using FromStr.
use clap::{Arg, Command};
fn main() {
let matches = Command::new("app")
.arg(Arg::new("config")
.short('c')
.long("config")
.takes_value(true))
.get_matches_from(["app", "--config", "settings.toml"]);
// get_one returns Option<&T>
let config: Option<&String> = matches.get_one::<String>("config");
if let Some(path) = config {
println!("Config file: {}", path);
}
}get_one returns a single optional value for the argument.
use clap::{Arg, Command};
fn main() {
let matches = Command::new("app")
.arg(Arg::new("file")
.short('f')
.long("file")
.takes_value(true)
.multiple_occurrences(true))
.get_matches_from(["app", "-f", "a.txt", "-f", "b.txt", "-f", "c.txt"]);
// get_many returns Option<Iter<T>>
let files: Option<Vec<&String>> = matches.get_many::<String>("file")
.map(|iter| iter.collect());
if let Some(paths) = files {
println!("Files: {:?}", paths);
// Files: ["a.txt", "b.txt", "c.txt"]
}
}get_many returns an iterator over all values for the argument.
use clap::{Arg, Command};
fn main() {
let matches = Command::new("app")
.arg(Arg::new("level")
.short('l')
.long("level")
.takes_value(true)
.multiple_occurrences(true))
.get_matches_from(["app", "-l", "1", "-l", "2", "-l", "3"]);
// get_one returns only the LAST value
let level: Option<&String> = matches.get_one("level");
println!("Level: {:?}", level);
// Level: Some("3")
// Values "1" and "2" are lost
}get_one silently discards earlier values when multiple are provided.
use clap::{Arg, Command};
fn main() {
let matches = Command::new("app")
.arg(Arg::new("level")
.short('l')
.long("level")
.takes_value(true)
.multiple_occurrences(true))
.get_matches_from(["app", "-l", "1", "-l", "2", "-l", "3"]);
// get_many returns ALL values
let levels: Vec<&String> = matches.get_many("level")
.map(|iter| iter.collect())
.unwrap_or_default();
println!("Levels: {:?}", levels);
// Levels: ["1", "2", "3"]
}get_many preserves all provided values.
use clap::{Arg, Command};
fn main() {
let matches = Command::new("app")
.arg(Arg::new("port")
.short('p')
.long("port")
.takes_value(true)
.value_parser(clap::value_parser!(u16)))
.get_matches_from(["app", "--port", "8080"]);
// Type is inferred from value_parser
let port: Option<&u16> = matches.get_one("port");
// Or explicit type annotation
let port: Option<&u16> = matches.get_one::<u16>("port");
if let Some(p) = port {
println!("Port: {}", p);
}
}Both methods support typed parsing via value_parser or FromStr.
use clap::{Arg, Command};
fn main() {
let matches = Command::new("app")
.arg(Arg::new("numbers")
.short('n')
.long("number")
.takes_value(true)
.multiple_occurrences(true)
.value_parser(clap::value_parser!(i32)))
.get_matches_from(["app", "-n", "1", "-n", "2", "-n", "3"]);
let numbers: Vec<&i32> = matches.get_many("numbers")
.map(|iter| iter.collect())
.unwrap_or_default();
println!("Numbers: {:?}", numbers);
// Numbers: [1, 2, 3]
// Can iterate directly
if let Some(iter) = matches.get_many::<i32>("numbers") {
for num in iter {
println!("Number: {}", num);
}
}
}get_many returns typed values through iteration.
use clap::{Arg, Command};
fn main() {
let matches = Command::new("app")
.arg(Arg::new("config")
.long("config")
.takes_value(true)
.value_name("FILE")
.help("Path to configuration file"))
.get_matches();
// Config file path: use get_one
if let Some(config_path) = matches.get_one::<String>("config") {
println!("Using config: {}", config_path);
}
}Use get_one when the argument conceptually accepts one value.
use clap::{Arg, Command};
fn main() {
let matches = Command::new("concat")
.arg(Arg::new("files")
.takes_value(true)
.multiple_occurrences(true)
.value_name("FILE")
.help("Files to concatenate"))
.get_matches_from(["concat", "a.txt", "b.txt", "c.txt"]);
// Multiple files: use get_many
if let Some(files) = matches.get_many::<String>("files") {
for file in files {
println!("Processing: {}", file);
}
}
}Use get_many when the argument conceptually accepts multiple values.
use clap::{Arg, Command};
fn main() {
let matches = Command::new("app")
.arg(Arg::new("value")
.long("value")
.takes_value(true)
.multiple_occurrences(true))
.get_matches_from(["app", "--value", "a", "--value", "b"]);
// get_one returns Option<&T>
let one: Option<&String> = matches.get_one("value");
// get_many returns Option<impl Iterator<Item = &T>>
let many: Option<clap::parser::ValuesRef<'_, String>> = matches.get_many("value");
// Different lifetimes and semantics
// get_one: borrow of single value
// get_many: borrow of iterator over values
println!("One: {:?}", one);
if let Some(iter) = many {
let collected: Vec<_> = iter.collect();
println!("Many: {:?}", collected);
}
}get_one returns Option<&T>; get_many returns Option<Iter>.
use clap::{Arg, Command};
fn main() {
let matches = Command::new("app")
.arg(Arg::new("file")
.long("file")
.takes_value(true)
.multiple_occurrences(true))
.get_matches_from(["app"]);
// No value provided
let one: Option<&String> = matches.get_one("file");
let many = matches.get_many::<String>("file");
println!("One: {:?}", one); // None
println!("Many: {:?}", many); // None
// Both return None when argument not provided
// get_many returns None, not Some(empty_iter)
}Both return None when the argument wasn't provided.
use clap::{Arg, Command};
fn main() {
let matches = Command::new("app")
.arg(Arg::new("items")
.takes_value(true)
.multiple_occurrences(true))
.get_matches_from(["app", "a", "b", "c"]);
// Collect into Vec
let items: Vec<&String> = matches.get_many("items")
.map(|iter| iter.collect())
.unwrap_or_default();
// Or iterate directly
if let Some(iter) = matches.get_many::<String>("items") {
for item in iter {
println!("Item: {}", item);
}
}
}get_many results can be collected or iterated.
use clap::{Arg, Command};
fn main() {
let matches = Command::new("app")
.arg(Arg::new("timeout")
.long("timeout")
.takes_value(true)
.default_value("30")
.value_parser(clap::value_parser!(u64)))
.get_matches_from(["app"]);
// With default_value, always returns Some
let timeout: &u64 = matches.get_one("timeout").expect("has default");
println!("Timeout: {}s", timeout);
}Default values ensure get_one returns Some.
use clap::{Arg, Command};
fn main() {
let matches = Command::new("app")
.arg(Arg::new("hosts")
.long("host")
.takes_value(true)
.multiple_occurrences(true)
.default_value("localhost"))
.get_matches_from(["app"]);
// get_many returns the single default value
let hosts: Vec<&String> = matches.get_many("hosts")
.map(|iter| iter.collect())
.unwrap_or_default();
println!("Hosts: {:?}", hosts);
// Hosts: ["localhost"]
}Default values work with get_many as a single-value iterator.
use clap::{Arg, Command};
fn main() {
let matches = Command::new("app")
.arg(Arg::new("files")
.takes_value(true)
.multiple_occurrences(true)
.value_delimiter(',')) // Parse comma-separated values
.get_matches_from(["app", "--files", "a.txt,b.txt,c.txt"]);
// Delimiter creates multiple values from single argument
let files: Vec<&String> = matches.get_many("files")
.map(|iter| iter.collect())
.unwrap_or_default();
println!("Files: {:?}", files);
// Files: ["a.txt", "b.txt", "c.txt"]
}value_delimiter splits single argument into multiple values.
use clap::{Arg, Command};
fn main() {
// multiple_occurrences: -f a.txt -f b.txt
let matches1 = Command::new("app")
.arg(Arg::new("file")
.short('f')
.takes_value(true)
.multiple_occurrences(true))
.get_matches_from(["app", "-f", "a.txt", "-f", "b.txt"]);
// multiple_values: -f a.txt b.txt
let matches2 = Command::new("app")
.arg(Arg::new("file")
.short('f')
.takes_value(true)
.multiple_values(true)) // Deprecated: use .action(ArgAction::Append)
.try_get_matches_from(["app", "-f", "a.txt", "b.txt"]);
// Both cases: use get_many
// multiple_occurrences allows repeated flags
// multiple_values allows multiple values after single flag
}Both patterns require get_many to access all values.
use clap::{Arg, Command};
fn main() {
let matches = Command::new("app")
.arg(Arg::new("files")
.takes_value(true)
.multiple_occurrences(true)
.index(1)) // Positional argument
.get_matches_from(["app", "file1.txt", "file2.txt", "file3.txt"]);
let files: Vec<&String> = matches.get_many("files")
.map(|iter| iter.collect())
.unwrap_or_default();
println!("Files: {:?}", files);
// Files: ["file1.txt", "file2.txt", "file3.txt"]
}Positional arguments with multiple_occurrences also use get_many.
use clap::{Arg, Command};
fn main() {
let result = Command::new("app")
.arg(Arg::new("port")
.long("port")
.takes_value(true)
.value_parser(clap::value_parser!(u16)))
.try_get_matches_from(["app", "--port", "not_a_number"]);
match result {
Ok(matches) => {
let port: Option<&u16> = matches.get_one("port");
println!("Port: {:?}", port);
}
Err(e) => {
// Type parsing error is caught during argument parsing
println!("Error: {}", e);
// Error: Invalid value "not_a_number" for "port": could not parse...
}
}
}Type parsing errors are caught during argument parsing, not get_one.
use clap::{Arg, Command};
fn main() {
let matches = Command::new("app")
.arg(Arg::new("files")
.takes_value(true)
.multiple_occurrences(true))
.get_matches_from(["app", "a.txt", "b.txt", "c.txt"]);
// Enumerate for index access
if let Some(iter) = matches.get_many::<String>("files") {
for (idx, file) in iter.enumerate() {
println!("File {}: {}", idx, file);
}
}
// Or collect for indexed access
let files: Vec<&String> = matches.get_many("files")
.map(|iter| iter.collect())
.unwrap_or_default();
if files.len() > 1 {
println!("Second file: {}", files[1]);
}
}Collect into Vec for indexed access to values.
use clap::{Arg, Command};
fn main() {
let matches = Command::new("app")
.arg(Arg::new("verbose")
.short('v')
.takes_value(false)
.action(clap::ArgAction::Count))
.get_matches_from(["app", "-v", "-v", "-v"]);
// For Count action, use get_one with u8 type
let count: u8 = *matches.get_one("verbose").unwrap_or(&0);
println!("Verbosity level: {}", count);
// Verbosity level: 3
}For counting flag occurrences, use ArgAction::Count with get_one.
use clap::{Arg, Command};
fn main() {
let mut matches = Command::new("app")
.arg(Arg::new("file")
.takes_value(true)
.multiple_occurrences(true))
.get_matches_from(["app", "a.txt", "b.txt"]);
// get_many borrows, remove_many takes ownership
let files: Vec<String> = matches.remove_many("file")
.map(|iter| iter.collect())
.unwrap_or_default();
// After remove_many, get_many returns None
let files_again: Option<clap::parser::ValuesRef<'_, String>> = matches.get_many("file");
println!("After removal: {:?}", files_again); // None
}remove_many extracts values, leaving None in the matches.
The choice between get_one and get_many depends on the semantics of your argument:
get_one retrieves the last value for an argument, appropriate when the argument conceptually has one value. Even if users provide multiple values, only the last is returned. Use this for configuration paths, timeout values, log levels, and other single-value settings.
get_many retrieves all values for an argument, returning an iterator. Use this when the argument represents a collection: input files, include paths, feature flags, or any case where multiple values make sense together. The iterator can be collected into Vec or processed directly.
Key distinctions:
get_one returns Option<&T>; get_many returns Option<ValuesRef<'_, T>>get_one discards earlier values; get_many preserves all valuesFromStr or value_parser for type conversionNone when the argument wasn't providedBest practice: Match the retrieval method to your argument's semantics. If providing multiple values would be an error, validate after get_many to ensure exactly one value. If multiple values are valid and meaningful, use get_many to process the collection. The multiple_occurrences(true) or multiple_values(true) argument configuration suggests get_many, but you can use eitherāthe difference is what data you can access.