4.2 rust 命令行参数
自定义的命令行参数解析
这是本人自己写的一套方法,用着感觉比较舒服,官方的参数解析请跳过此部分看后面的部分
#![allow(unused)] use std::env; extern crate mij; use mij::base::arg; fn parse_args(mut num:&mut i32,mut num2:&mut f64,mut ss:&mut String,mut flag:&mut bool){ let mut sc = arg::StrParse::new(); sc.to_i32(num,"-a","-1","描述1"); sc.to_f64(num2,"-ft","0.0","描述1"); sc.to_string(ss,"-f","/tmp/t.txt","file"); sc.to_bool(flag,"-c","true","bool value") } fn main() { let mut aa = 0; let mut ff = 0.0; let mut ss = String::new(); let mut flag = false; println!("-------------------------------"); parse_args(&mut aa,&mut ff,&mut ss,&mut flag); println!("a={:?},ft={},b={:?},flag={}",aa,ff,ss,flag); }
cargo run输出,即全部输出默认值
------------------------------- a=-1,ft=0,b="/tmp/t.txt",flag=false
指定参数,参数之间无顺序,参数类型包含整数,浮点,字符串,布尔四类,日常够用
$ ./target/debug/store -a 4 -c -f "/tmp/b.txt" -ft 3.3 ------------------------------- a=4,ft=3.3,b="/tmp/b.txt",flag=true
这样就从外部对程序提供了各种类型的参数,需要什么类型,调用相应的类型方法,灵活性很强
解析部分代码如下,还差了-h帮助功能,输出各种参数的意义这么一个辅助功能,后续有时间再加,先这样用着...
use std::env; #[derive(Debug, Clone)] pub struct StrParse { args: Vec<String>, } impl StrParse { pub fn new() -> StrParse { let mut sc = StrParse { args: env::args().collect(), }; sc } pub fn to_i32(&self, mut data: &mut i32,flag:&str,default_value:&str,desc:&str){ let mut not_has = true; for (index,val) in self.args.iter().enumerate() { if index>0{ let data_flag = flag; if val == data_flag{ not_has = false; // println!("{:#?}:{:#?}",val,args[index+1]); *data = (self.args[index+1]).parse().expect("Not a number!"); break; } } } if not_has { *data = default_value.parse().expect("Not a number!"); } } pub fn to_f64(&self, mut data: &mut f64,flag:&str,default_value:&str,desc:&str){ let mut not_has = true; for (index,val) in self.args.iter().enumerate() { if index>0{ let data_flag = flag; if val == data_flag{ not_has = false; // println!("{:#?}:{:#?}",val,args[index+1]); *data = (self.args[index+1]).parse().expect("Not a number!"); break; } } } if not_has { *data = default_value.parse().expect("Not a number!"); } } pub fn to_string(&self, mut data: &mut String,flag:&str,default_value:&str,desc:&str){ let mut not_has = true; for (index,val) in self.args.iter().enumerate() { if index>0{ let data_flag = flag; if val == data_flag{ not_has = false; // println!("{:#?}:{:#?}",val,args[index+1]); *data = String::from(&self.args[index+1]); break; } } } if not_has { *data = String::from(default_value); } } pub fn to_bool(&self, mut data: &mut bool,flag:&str,default_value:&str,desc:&str){ let mut not_has = true; for (index,val) in self.args.iter().enumerate() { if index>0{ let data_flag = flag; if val == data_flag{ not_has = false; let mut v = false; if default_value == "true" { v = true; } *data = v; break; } } } if not_has { *data = false; } } }
官方内容开始,官方是绑定一个对象,并加一些错误处理,每次都要定义新的对象与对应的数据类型,感觉好麻烦,没法忍...于是就写了上面的方法
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
从命令行读取参数
use std::env; fn main() { let args: Vec<String> = env::args().collect(); println!("{:?}", args); }
ai@aisty:/opt/wks/rust/rfil/rcmd/target/debug$ ./rcmd aa bb cc ["./rcmd", "aa", "bb", "cc"]
第一个参数是命令本身
The
args
Function and Invalid UnicodeNote that
std::env::args
will panic if any argument contains invalid Unicode. If your program needs to accept arguments containing invalid Unicode, usestd::env::args_os
instead. That function returns an iterator that producesOsString
values instead ofString
values. We’ve chosen to usestd::env::args
here for simplicity, becauseOsString
values differ per platform and are more complex to work with thanString
values.
索引为0的参数是命令本身,从索引为1的参数开始才是输入的参数
use std::env; fn main() { let args: Vec<String> = env::args().collect(); let query = &args[1]; let filename = &args[2]; println!("Searching for {}", query); println!("In file {}", filename); }
ai@aisty:/opt/wks/rust/rfil/rcmd$ cargo run name /tmp/aa.txt Finished dev [unoptimized + debuginfo] target(s) in 0.00s Running `target/debug/rcmd name /tmp/aa.txt` Searching for name In file /tmp/aa.txt
读取指定的文件内容
use std::env; use std::fs; fn main() { let args: Vec<String> = env::args().collect(); let filename = &args[1]; println!("In file {}", filename); let contents = fs::read_to_string(filename) .expect("Something went wrong reading the file"); println!("With text:\n{}", contents); }
ai@aisty:/opt/wks/rust/rfil/rcmd$ cargo run /tmp/aa.txt Compiling rcmd v0.1.0 (/opt/wks/rust/rfil/rcmd) Finished dev [unoptimized + debuginfo] target(s) in 0.21s Running `target/debug/rcmd /tmp/aa.txt` In file /tmp/aa.txt With text: aa
use std::env; use std::fs; fn main() { let args: Vec<String> = env::args().collect(); let (query, filename) = parse_config(&args); // --snip-- println!("Searching for {}", query); println!("In file {}", filename); let contents = fs::read_to_string(filename) .expect("Something went wrong reading the file"); println!("With text:\n{}", contents); } fn parse_config(args: &[String]) -> (&str, &str) { let query = &args[1]; let filename = &args[2]; (query, filename) }
ai@aisty:/opt/wks/rust/rfil/rcmd$ cargo run aa /tmp/aa.log Finished dev [unoptimized + debuginfo] target(s) in 0.00s Running `target/debug/rcmd aa /tmp/aa.log` Searching for aa In file /tmp/aa.log With text: aa bb
use std::env; use std::fs; fn main() { let args: Vec<String> = env::args().collect(); let config = parse_config(&args); println!("Searching for {}", config.query); println!("In file {}", config.filename); let contents = fs::read_to_string(config.filename) .expect("Something went wrong reading the file"); println!("With text:\n{}", contents); } struct Config { query: String, filename: String, } fn parse_config(args: &[String]) -> Config { let query = args[1].clone(); let filename = args[2].clone(); Config { query, filename } }
clone性能不好,后面会介绍其他方式
There’s a tendency among many Rustaceans to avoid using clone
to fix ownership problems because of its runtime cost.
use std::env; use std::fs; fn main() { let args: Vec<String> = env::args().collect(); let config = Config::new(&args); println!("Searching for {}", config.query); println!("In file {}", config.filename); let contents = fs::read_to_string(config.filename) .expect("Something went wrong reading the file"); println!("With text:\n{}", contents); } struct Config { query: String, filename: String, } impl Config { fn new(args: &[String]) -> Config { let query = args[1].clone(); let filename = args[2].clone(); Config { query, filename } } }
添加自定义错误
use std::env; use std::fs; fn main() { let args: Vec<String> = env::args().collect(); let config = Config::new(&args); println!("Searching for {}", config.query); println!("In file {}", config.filename); let contents = fs::read_to_string(config.filename) .expect("Something went wrong reading the file"); println!("With text:\n{}", contents); } struct Config { query: String, filename: String, } impl Config { fn new(args: &[String]) -> Config { if args.len() < 3 { panic!("not enough arguments"); } let query = args[1].clone(); let filename = args[2].clone(); Config { query, filename } } }
Returning a Result
from new
Instead of Calling panic!