[英]Can I simplify this Rust code dealing with Option<T> and Result<T>?
I'm working on my first actual Rust program, a custom i3status. 我正在研究我的第一个实际的Rust程序,一个自定义的i3status。 It's coming along nicely, but there's two places where I have to deal with
Result<T>
and Option<T>
and the code looks really ugly, leading me to believe that I've missed some language feature or library function for writing these parts more cleanly. 它很顺利,但有两个地方我必须处理
Result<T>
和Option<T>
并且代码看起来非常难看,让我相信我错过了一些语言功能或库函数来编写这些部分更干净。
This is the file in question , but I'll quote the relevant parts here. 这是有问题的文件 ,但我会在这里引用相关部分。 The first one is this:
第一个是:
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,
}
}
Swallowing error messages here is intentional. 这里吞咽错误信息是故意的。 An i3status does not have an stderr, so all I can do is skip rendering of the broken parts.
i3status没有stderr,所以我所能做的就是跳过渲染损坏的部分。
Regardless of that, this code looks ugly, with its repeated use of match
to discard Err
values. 无论如何,这段代码看起来很丑陋,重复使用
match
来丢弃Err
值。 I tried to use the new ?
我试过用新的
?
operator by making the return type a std::io::Result<i64>
, but str::parse
returns a different type of error, so that doesn't work AFAICS. 通过使返回类型为
std::io::Result<i64>
,但str::parse
返回不同类型的错误,因此std::io::Result<i64>
不起作用。 I therefore went with Option<i64>
as the lowest common denominator. 因此,我将
Option<i64>
作为最低标准。
The second ugly part is where this function gets used: 第二个丑陋的部分是使用此函数的地方:
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(),
};
I feel like one should be able to contract each of the match
expressions into a function call like .or_else()
, but .or_else(|| return Vec::new())
obviously won't work since the return
is scoped to the lambda instead of the original function. 我觉得应该能够将每个
match
表达式收缩到像.or_else()
类的函数调用中,但是.or_else(|| return Vec::new())
显然不起作用,因为return
的作用域是lambda而不是原始函数。
So, in both cases, my question is whether I can replace match
by something more compact and idiomatic. 所以,在这两种情况下,我的问题是我是否可以通过更紧凑和惯用的东西来取代
match
。
To combine Option<T>
s with Result<T, E>
s, use ok()
and the question mark operator: 要将
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()
}
As for the second part of the question, if you can contain all those variable bindings in a single function: 至于问题的第二部分,如果你可以在一个函数中包含所有这些变量绑定:
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
}
You can then use unwrap_or_else()
on its result to return an empty Vec
upon any error: 然后,您可以在其结果上使用
unwrap_or_else()
以在出现任何错误时返回空Vec
:
let foo = foo().unwrap_or_else(|| vec![]);
Or just unwrap_or()
, because empty vectors don't allocate memory : 或者只是
unwrap_or()
,因为空向量不分配内存 :
let foo = foo().unwrap_or(vec![]);
For the second part, you can use one of the comprehension crates available on crates.io like map_for , comp or mdo . 对于第二部分,您可以使用crates.io上提供的其中一个理解包,例如map_for , comp或mdo 。 For example with
map_for
: 例如,使用
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![]);
Full disclosure: I am the author of the map_for
crate. 完全披露:我是
map_for
箱子的作者。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.