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 Unicode

Note that std::env::args will panic if any argument contains invalid Unicode. If your program needs to accept arguments containing invalid Unicode, use std::env::args_os instead. That function returns an iterator that produces OsString values instead of String values. We’ve chosen to use std::env::args here for simplicity, because OsString values differ per platform and are more complex to work with than String 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!

 

posted @ 2021-09-28 14:48  方诚  阅读(768)  评论(0编辑  收藏  举报