建设商务网站目的及功能定位,惠州专业网站建设公司哪里有,如何在服务器里建设网站,石家庄建站网页模板写web项目或者app等#xff0c;必不可少的要接受参数和校验参数的准确性#xff0c;基本也是项目开始的第一步#xff0c;那么我们今天来看下rust提供了哪些优秀的crates 关注 vx golang技术实验室#xff0c;获取更多golang、rust好文 Part1一、clap_v3 本来是想用structO… 写web项目或者app等必不可少的要接受参数和校验参数的准确性基本也是项目开始的第一步那么我们今天来看下rust提供了哪些优秀的crates 关注 vx golang技术实验室获取更多golang、rust好文 Part1一、clap_v3 本来是想用structOpt但是看文档是这样描述的 由于 clap v3 现已发布并且 structopt 功能已集成几乎按原样因此 structopt 现在处于维护模式不会添加新功能。 错误将被修复文档改进将被接受。 11. 1 添加依赖 [dependencies]clap { version 4.2.7, features [derive,cargo] }features 0.10.0cargo 0.70.1或者cargo add clap -- features cargo需要注意如果不启用 cargo feature 则会报如下错误。requires cargo feature 如果使用command!、arg! 必须在features 中添加cargo 21.2 快速启动 use std::env::Args;/// clap_v3 原来的structOpt //use std::path::PathBuf;use clap::{arg, command, value_parser, ArgAction, Command};fn test() { let matches command!() // requires cargo feature .arg(arg!([name] Optional name to operate on)) .arg( arg!( -c --config FILE Sets a custom config file ) // We dont have syntax yet for optional options, so manually calling required .required(false) .value_parser(value_parser!(PathBuf)), ) .arg(arg!( -d --debug ... Turn debugging information on )) .subcommand( Command::new(test) .about(does testing things) .arg(arg!(-l --list lists test values).action(ArgAction::SetTrue)), ) .get_matches(); // You can check the value provided by positional arguments, or option arguments if let Some(name) matches.get_one::String(name) { println!(Value for name: {name}); } if let Some(config_path) matches.get_one::PathBuf(config) { println!(Value for config: {}, config_path.display()); } // You can see how many times a particular flag or argument occurred // Note, only flags can have multiple occurrences match matches .get_one::u8(debug) .expect(Counts are defaulted) { 0 println!(Debug mode is off), 1 println!(Debug mode is kind of on), 2 println!(Debug mode is on), _ println!(Dont be crazy), } // You can check for the existence of subcommands, and if found use their // matches just as you would the top level cmd if let Some(matches) matches.subcommand_matches(test) { // $ myapp test was run if matches.get_flag(list) { // $ myapp test -l was run println!(Printing testing lists...); } else { println!(Not printing testing lists...); } } // Continued program logic goes here...}pub fn claps(){ test()} 1、默认执行情况 cargo runDebug mode is off 2、参看帮助文档 cargo run --helpRun a binary or example of the local packageUsage: cargo run [OPTIONS] [args]...Arguments: [args]... Arguments for the binary or example to runOptions: -q, --quiet Do not print cargo log messages --bin [NAME] Name of the bin target to run --example [NAME] Name of the example target to run -p, --package [SPEC] Package with the target to run -j, --jobs N Number of parallel jobs, defaults to # of CPUs. --keep-going Do not abort the build as soon as there is an error (unstable) -r, --release Build artifacts in release mode, with optimizations --profile PROFILE-NAME Build artifacts with the specified profile -F, --features FEATURES Space or comma separated list of features to activate --all-features Activate all available features --no-default-features Do not activate the default feature --target TRIPLE Build for the target triple --target-dir DIRECTORY Directory for all generated artifacts --manifest-path PATH Path to Cargo.toml --message-format FMT Error format --unit-graph Output build graph in JSON (unstable) --ignore-rust-version Ignore rust-version specification in packages --timings[FMTS] Timing output formats (unstable) (comma separated): html, json -h, --help Print help -v, --verbose... Use verbose output (-vv very verbose/build.rs output) --color WHEN Coloring: auto, always, never --frozen Require Cargo.lock and cache are up to date --locked Require Cargo.lock is up to date --offline Run without accessing the network --config KEYVALUE Override a configuration value -Z FLAG Unstable (nightly-only) flags to Cargo, see cargo -Z help for detailsRun cargo help run for more detailed information. 3、使用 -dd 参数 cargo run -- -dd test Debug mode is onNot printing testing lists... 31.3 command 解析器 1.3.1 基本使用 fn command(){ let matches Command::new(MyApp) .version(1.0) .author(ZHangQL Z ZQLgmail.com) .about(this is the test project) .args([//次数是args如果单个的的arg arg!(--config FILE a required file for the configuration and no short). required(true)//必须包含 .require_equals(true)//要求使用等号赋值 // .default_value() //设置默认值 , arg!(-d --debug ... turns on debugging information and allows multiples), arg!([input] an optional input file to use) ]) .arg(arg!(--two VALUE).required(true))//单个的 .get_matches(); println!( config: {:?}, matches.get_one::String(config).expect(required) ); println!( debug: {:?}, matches.get_one::String(debug) ); println!( input: {:?}, matches.get_one::String(input) );} 查看help RUST_BACKTRACE1 cargo run -- --helpthis is the test projectUsage: my_test [OPTIONS] --configFILE --two VALUE [input]Arguments: [input] an optional input file to useOptions: --configFILE a required file for the configuration and no short -d, --debug... turns on debugging information and allows multiples --two VALUE -h, --help Print help -V, --version Print version 运行 RUST_BACKTRACE1 cargo run -- --config./config.yaml --two rrr lllllconfig: ./config.yamltwo: Some(rrr)input: Some(lllll) 1.3.2 使用command!构建解析器 你也可以使用 command! 宏 构建解析器不过要想使用 command! 宏你需要开启 cargo feature。 use clap::{arg, command};fn main() { // requires cargo feature, reading name, version, author, and description from Cargo.toml let matches command!() .arg(arg!(--two VALUE).required(true)) .arg(arg!(--one VALUE).required(true)) .get_matches(); println!( two: {:?}, matches.get_one::String(two).expect(required) ); println!( one: {:?}, matches.get_one::String(one).expect(required) );} 1.3.3 Command::next_line_help 使用 Command::next_line_help 方法 可以修改参数打印行为 use clap::{arg, command, ArgAction};fn main() { let matches command!() // requires cargo feature .next_line_help(true) .arg(arg!(--two VALUE).required(true).action(ArgAction::Set)) .arg(arg!(--one VALUE).required(true).action(ArgAction::Set)) .get_matches(); println!( two: {:?}, matches.get_one::String(two).expect(required) ); println!( one: {:?}, matches.get_one::String(one).expect(required) );} Usage: my_test [OPTIONS] --configFILE --two VALUE [input]Arguments: [input] an optional input file to useOptions: --configFILE a required file for the configuration and no short -d, --debug... turns on debugging information and allows multiples --two VALUE -h, --help Print help -V, --version Print version 效果就是参数的描述和参数是分行的描述信息在参数下一行。 41.4 添加命令行参数Adding Arguments 我们可以使用 Command::arg 方法来添加 Arg 对象来添加命令行参数 fn adding_arg(){ let matches command!() .arg(Arg::new(name)) .get_matches(); println!(name: {:?}, matches.get_one::String(name));} 查看help RUST_BACKTRACE1 cargo run -- --helpUsage: my_test [name]Arguments: [name] Options: -h, --help Print help -V, --version Print version 2、使用 name 参数默认 cargo runname: None 3、使用 name 参数blob 注意定义的时候没有是直接使用的 不需要key的 cargo run bobname: Some(bob) 1.4.2 设置参数行为 需要注意参数默认值是一个 Set 类型 我们可以使用 Command::action 方法来设置 参数行为。如果可以添加多个只我们可以使用 ArgAction::Append use clap::{command, Arg, ArgAction};fn main() { let matches command!() // requires cargo feature .arg(Arg::new(name).action(ArgAction::Append)) .get_matches(); let args matches .get_many::String(name) .unwrap_or_default() .map(|v| v.as_str()) .collect::Vec_(); println!(names: {:?}, args);} 51.5 参数选项 一个参数行为的标志 顺序无关 可选参数 意图清晰 fn arg_switch(){ let matches command!() .arg(Arg::new(name) .short(n) .long(name) ).get_matches(); println!(name: {:?}, matches.get_one::String(name));} 上述代码我们定义了一个name参数缩写是n全拼是name也就是如下形式 -n, --name name 我们使用方式就有如下几种 cargo run -- --name blocargo run -- --nameblobcargo run -- -n blobcargo run -- -nblobcargo run -- -nblob 1.5.1 开启/关闭标志 我们可以是 ArgAction::SetTrue 开启参数 use clap::{command, Arg, ArgAction};fn main() { let matches command!() // requires cargo feature .arg( Arg::new(verbose) .short(v) .long(verbose) .action(ArgAction::SetTrue), ) .get_matches(); println!(verbose: {:?}, matches.get_flag(verbose));} 1.5.2参数调用计数 我们可以使用 ArgAction::Count use clap::{command, Arg, ArgAction};fn main() { let matches command!() // requires cargo feature .arg( Arg::new(verbose) .short(v) .long(verbose) .action(ArgAction::Count), ) .get_matches(); println!(verbose: {:?}, matches.get_count(verbose));} 默认值是0多次使用参数就会计数 cargo run -- --verbose --verbose 1.5.3 默认值 fn default_value(){ let matches command!() // requires cargo feature .arg( arg!([PORT]) .value_parser(value_parser!(u16)) .default_value(2023), ) .get_matches(); println!( port: {:?}, matches .get_one::u16(PORT) .expect(default ensures there is always a value) );} cargo runport: 2023cargo run 897port: 897 1.5.4 参数校验 默认情况下参数被认为是 String并且使用 UTF-8 校验。 枚举值 fn enum_check(){ let matches command!() // requires cargo feature .arg( arg!(MODE) .help(What mode to run the program in) .value_parser([fast, slow]), ) .get_matches(); // Note, its safe to call unwrap() because the arg is required match matches .get_one::String(MODE) .expect(MODE is required and parsing will fail if its missing) .as_str() { fast { println!(Hare); } slow { println!(Tortoise); } _ unreachable!(), }} cargo run rrr error: invalid value rrr for MODE [possible values: fast, slow]cargo run fastHare 如果我们开启了 derive feature 则我们也可以实现 ValueEnum 特征实现相同的功能 use clap::{arg, builder::PossibleValue, command, value_parser, ValueEnum};#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]enum Mode { Fast, Slow,}// Can also be derived with feature flag deriveimpl ValueEnum for Mode { fn value_variantsa() - a [Self] { [Mode::Fast, Mode::Slow] } fn to_possible_valuea(self) - OptionPossibleValue { Some(match self { Mode::Fast PossibleValue::new(fast).help(Run swiftly), Mode::Slow PossibleValue::new(slow).help(Crawl slowly but steadily), }) }}impl std::fmt::Display for Mode { fn fmt(self, f: mut std::fmt::Formatter_) - std::fmt::Result { self.to_possible_value() .expect(no values are skipped) .get_name() .fmt(f) }}impl std::str::FromStr for Mode { type Err String; fn from_str(s: str) - ResultSelf, Self::Err { for variant in Self::value_variants() { if variant.to_possible_value().unwrap().matches(s, false) { return Ok(*variant); } } Err(format!(invalid variant: {s})) }}fn main() { let matches command!() // requires cargo feature .arg( arg!(MODE) .help(What mode to run the program in) .value_parser(value_parser!(Mode)), ) .get_matches(); // Note, its safe to call unwrap() because the arg is required match matches .get_one::Mode(MODE) .expect(MODE is required and parsing will fail if its missing) { Mode::Fast { println!(Hare); } Mode::Slow { println!(Tortoise); } }} 1.5.5 校验值 我们可以使用 Arg::value_parser 验证并解析成我们需要的任何类型。 fn validated(){ let matches command!() // requires cargo feature .arg( arg!(PORT) .help(Network port to use) .value_parser(value_parser!(u16).range(1..)), ) .get_matches(); // Note, its safe to call unwrap() because the arg is required let port: u16 *matches .get_one::u16(PORT) .expect(PORT is required and parsing will fail if its missing); println!(PORT {port});}cargo run 0error: invalid value 0 for PORT: 0 is not in 1..65535cargo run 1PORT 10 1.5.6 自定义解析器 我们也可以使用自定义解析器用于改进错误信息提示和额外的验证。 use std::ops::RangeInclusive;use clap::{arg, command};fn main() { let matches command!() // requires cargo feature .arg( arg!(PORT) .help(Network port to use) .value_parser(port_in_range), ) .get_matches(); // Note, its safe to call unwrap() because the arg is required let port: u16 *matches .get_one::u16(PORT) .expect(PORT is required and parsing will fail if its missing); println!(PORT {port});}const PORT_RANGE: RangeInclusiveusize 1..65535;fn port_in_range(s: str) - Resultu16, String { let port: usize s .parse() .map_err(|_| format!({s} isnt a port number))?; if PORT_RANGE.contains(port) { Ok(port as u16) } else { Err(format!( port not in range {}-{}, PORT_RANGE.start(), PORT_RANGE.end() )) }} 1.5。7 参数关系(Argument Relations) 我们可以声明 Arg 和 ArgGroup。ArgGroup 用于声明参数关系。 use std::path::PathBuf;use clap::{arg, command, value_parser, ArgAction, ArgGroup};fn main() { // Create application like normal let matches command!() // requires cargo feature // Add the version arguments .arg(arg!(--set-ver VER set version manually)) .arg(arg!(--major auto inc major).action(ArgAction::SetTrue)) .arg(arg!(--minor auto inc minor).action(ArgAction::SetTrue)) .arg(arg!(--patch auto inc patch).action(ArgAction::SetTrue)) // Create a group, make it required, and add the above arguments .group( ArgGroup::new(vers) .required(true) .args([set-ver, major, minor, patch]), ) // Arguments can also be added to a group individually, these two arguments // are part of the input group which is not required .arg( arg!([INPUT_FILE] some regular input) .value_parser(value_parser!(PathBuf)) .group(input), ) .arg( arg!(--spec-in SPEC_IN some special input argument) .value_parser(value_parser!(PathBuf)) .group(input), ) // Now lets assume we have a -c [config] argument which requires one of // (but **not** both) the input arguments .arg( arg!(config: -c CONFIG) .value_parser(value_parser!(PathBuf)) .requires(input), ) .get_matches(); // Lets assume the old version 1.2.3 let mut major 1; let mut minor 2; let mut patch 3; // See if --set-ver was used to set the version manually let version if let Some(ver) matches.get_one::String(set-ver) { ver.to_owned() } else { // Increment the one requested (in a real program, wed reset the lower numbers) let (maj, min, pat) ( matches.get_flag(major), matches.get_flag(minor), matches.get_flag(patch), ); match (maj, min, pat) { (true, _, _) major 1, (_, true, _) minor 1, (_, _, true) patch 1, _ unreachable!(), }; format!({major}.{minor}.{patch}) }; println!(Version: {version}); // Check for usage of -c if matches.contains_id(config) { let input matches .get_one::PathBuf(INPUT_FILE) .unwrap_or_else(|| matches.get_one::PathBuf(spec-in).unwrap()) .display(); println!( Doing work using input {} and config {}, input, matches.get_one::PathBuf(config).unwrap().display() ); }} 此时 --set-ver |--major|--minor|--patch 是一个组的参数。 1.5.8 自定义校验(Custom Validation) 我们可以创建自定义校验错误 Command::error 方法可以返回指定错误 Error和自定义错误信息 use std::path::PathBuf;use clap::error::ErrorKind;use clap::{arg, command, value_parser, ArgAction};fn main() { // Create application like normal let mut cmd command!() // requires cargo feature // Add the version arguments .arg(arg!(--set-ver VER set version manually)) .arg(arg!(--major auto inc major).action(ArgAction::SetTrue)) .arg(arg!(--minor auto inc minor).action(ArgAction::SetTrue)) .arg(arg!(--patch auto inc patch).action(ArgAction::SetTrue)) // Arguments can also be added to a group individually, these two arguments // are part of the input group which is not required .arg(arg!([INPUT_FILE] some regular input).value_parser(value_parser!(PathBuf))) .arg( arg!(--spec-in SPEC_IN some special input argument) .value_parser(value_parser!(PathBuf)), ) // Now lets assume we have a -c [config] argument which requires one of // (but **not** both) the input arguments .arg(arg!(config: -c CONFIG).value_parser(value_parser!(PathBuf))); let matches cmd.get_matches_mut(); // Lets assume the old version 1.2.3 let mut major 1; let mut minor 2; let mut patch 3; // See if --set-ver was used to set the version manually let version if let Some(ver) matches.get_one::String(set-ver) { if matches.get_flag(major) || matches.get_flag(minor) || matches.get_flag(patch) { cmd.error( ErrorKind::ArgumentConflict, Cant do relative and absolute version change, ) .exit(); } ver.to_string() } else { // Increment the one requested (in a real program, wed reset the lower numbers) let (maj, min, pat) ( matches.get_flag(major), matches.get_flag(minor), matches.get_flag(patch), ); match (maj, min, pat) { (true, false, false) major 1, (false, true, false) minor 1, (false, false, true) patch 1, _ { cmd.error( ErrorKind::ArgumentConflict, Can only modify one version field, ) .exit(); } }; format!({major}.{minor}.{patch}) }; println!(Version: {version}); // Check for usage of -c if matches.contains_id(config) { let input matches .get_one::PathBuf(INPUT_FILE) .or_else(|| matches.get_one::PathBuf(spec-in)) .unwrap_or_else(|| { cmd.error( ErrorKind::MissingRequiredArgument, INPUT_FILE or --spec-in is required when using --config, ) .exit() }) .display(); println!( Doing work using input {} and config {}, input, matches.get_one::PathBuf(config).unwrap().display() ); }} 61.6、子命令(Subcommand) 我们可以使用 Command::subcommand 方法添加子命令。每一个子命令都自己的版本、作者、参数和它的子命令。 use clap::{arg, command, Command};fn main() { let matches command!() // requires cargo feature .propagate_version(true) .subcommand_required(true) .arg_required_else_help(true) .subcommand( Command::new(add) .about(Adds files to myapp) .arg(arg!([NAME])), ) .get_matches(); match matches.subcommand() { Some((add, sub_matches)) println!( myapp add was used, name is: {:?}, sub_matches.get_one::String(NAME) ), _ unreachable!(Exhausted list of subcommands and subcommand_required prevents None), }} 我们使用 Command::arg_required_else_help 如果参数不存在优雅的退出。 使用 Command::propagate_version 可以打印命令的版本号 71.7、测试 我们可以使用 debug_assert! 宏 或者 使用 Command::debug_assert 方法。 use clap::{arg, command, value_parser};fn main() { let matches cmd().get_matches(); // Note, its safe to call unwrap() because the arg is required let port: usize *matches .get_one::usize(PORT) .expect(PORT is required and parsing will fail if its missing); println!(PORT {port});}fn cmd() - clap::Command { command!() // requires cargo feature .arg( arg!(PORT) .help(Network port to use) .value_parser(value_parser!(usize)), )}#[test]fn verify_cmd() { cmd().debug_assert();} 本文由 mdnice 多平台发布