天天看點

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!