自定義的指令行參數解析
這是本人自己寫的一套,用着感覺比較舒服,官方的參數解析請跳過此部分看後面的部分
#![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
Note thatFunction and Invalid Unicode
args
will panic if any argument contains invalid Unicode. If your program needs to accept arguments containing invalid Unicode, use
std::env::args
instead. That function returns an iterator that produces
std::env::args_os
values instead of
OsString
values. We’ve chosen to use
String
here for simplicity, because
std::env::args
values differ per platform and are more complex to work with than
OsString
values.
String
索引為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!
Result
new
panic!