簡體   English   中英

我可以簡化處理Option的Rust代碼 <T> 和結果 <T> ?

[英]Can I simplify this Rust code dealing with Option<T> and Result<T>?

我正在研究我的第一個實際的Rust程序,一個自定義的i3status。 它很順利,但有兩個地方我必須處理Result<T>Option<T>並且代碼看起來非常難看,讓我相信我錯過了一些語言功能或庫函數來編寫這些部分更干凈。

這是有問題的文件 ,但我會在這里引用相關部分。 第一個是:

fn read_number_from_file(path: &str) -> Option<i64> {
    let mut file = match File::open(path) {
        Ok(f) => f,
        Err(_) => return None,
    };
    let mut contents = String::new();
    match file.read_to_string(&mut contents) {
        Ok(_) => {},
        Err(_) => return None,
    };
    match contents.trim().parse::<i64>() {
        Ok(val) => Some(val),
        Err(_) => None,
    }
}

這里吞咽錯誤信息是故意的。 i3status沒有stderr,所以我所能做的就是跳過渲染損壞的部分。

無論如何,這段代碼看起來很丑陋,重復使用match來丟棄Err值。 我試過用新的? 通過使返回類型為std::io::Result<i64> ,但str::parse返回不同類型的錯誤,因此std::io::Result<i64>不起作用。 因此,我將Option<i64>作為最低標准。

第二個丑陋的部分是使用此函數的地方:

let energy_full = match read_number_from_file(ENERGY_FULL_PATH) {
    Some(val) => val,
    None      => return Vec::new(),
};
let energy_now = match read_number_from_file(ENERGY_NOW_PATH) {
    Some(val) => val,
    None      => return Vec::new(),
};
let is_charging = match read_number_from_file(POWER_ONLINE_PATH) {
    Some(val) => val > 0,
    None      => return Vec::new(),
};

我覺得應該能夠將每個match表達式收縮到像.or_else()類的函數調用中,但是.or_else(|| return Vec::new())顯然不起作用,因為return的作用域是lambda而不是原始函數。

所以,在這兩種情況下,我的問題是我是否可以通過更緊湊和慣用的東西來取代match

要將Option<T>Result<T, E> s組合,請使用ok()和問號運算符:

fn read_number_from_file(path: &str) -> Option<i64> {
    let mut file = File::open(path).ok()?;
    let mut contents = String::new();
    file.read_to_string(&mut contents).ok()?;
    contents.trim().parse::<i64>().ok()
}

至於問題的第二部分,如果你可以在一個函數中包含所有這些變量綁定:

fn foo() -> Option<Vec<i64>> { // or some other Option<Vec>
    let energy_full = read_number_from_file(ENERGY_FULL_PATH)?;
    let energy_now = read_number_from_file(ENERGY_NOW_PATH)?;
    let is_charging = read_number_from_file(POWER_ONLINE_PATH)? > 0;

    Some(Vec::new()) // placeholder for the valid return value
}

然后,您可以在其結果上使用unwrap_or_else()以在出現任何錯誤時返回空Vec

let foo = foo().unwrap_or_else(|| vec![]);

或者只是unwrap_or() ,因為空向量不分配內存

let foo = foo().unwrap_or(vec![]);

對於第二部分,您可以使用crates.io上提供的其中一個理解包,例如map_forcompmdo 例如,使用map_for

return map_for!(
    energy_full  <- read_number_from_file(ENERGY_FULL_PATH);
    energy_now   <- read_number_from_file(ENERGY_NOW_PATH);
    power_online <- read_number_from_file(POWER_ONLINE_PATH);
    is_charging  = power_online > 0;
    => vec![ energy_full, energy_now ]
).unwrap_or_else (|| vec![]);

完全披露:我是map_for箱子的作者。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM