ide*_*n42 8 variable-assignment rust
我有一段代码,需要一次分配多个可选变量.任何值都很少有机会None,因此单独处理每个失败的案例并不是特别有用.
目前我写这样的支票:
if let Some(a) = foo_a() {
if let Some(b) = foo_b() {
if let Some(c) = foo_c() {
if let Some(d) = foo_d() {
// code
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果可以对作业进行分组会很方便.如果没有这个,添加一个新变量会将块缩进一级,从而产生噪声差异并导致不必要的深度缩进:
if let Some(a) = foo_a() &&
let Some(b) = foo_b() &&
let Some(c) = foo_c() &&
let Some(d) = foo_d()
{
// code
}
Run Code Online (Sandbox Code Playgroud)
有没有办法Option在一个if语句中分配多个s?
一些值得注意的细节:
失败的第一个功能应该是短路而不是呼叫其他功能.否则,可以这样写:
if let (Some(a), Some(b), Some(c), Some(d)) = (foo_a(), foo_b(), foo_c(), foo_d()) {
// Code
}
Run Code Online (Sandbox Code Playgroud)
使用函数可以避免深度缩进,但我不想这样做,因为你可能不希望将主体放在不同的范围内......
fn my_function(a: Foo, b: Foo, c: Foo, d: Foo) {
// code
}
if let Some(a) = foo_a() {
if let Some(b) = foo_b() {
if let Some(c) = foo_c() {
if let Some(d) = foo_d() {
my_function(a, b, c, d);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
Eri*_*aas 10
正如@SplittyDev所说,你可以创建一个宏来获得你想要的功能.这是一个替代的基于宏的解决方案,它也保留了短路行为:
macro_rules! iflet {
([$p:pat = $e:expr] $($rest:tt)*) => {
if let $p = $e {
iflet!($($rest)*);
}
};
($b:block) => {
$b
};
}
fn main() {
iflet!([Some(a) = foo_a()] [Some(b) = foo_b()] [Some(c) = foo_c()] {
println!("{} {} {}", a, b, c);
});
}
Run Code Online (Sandbox Code Playgroud)
标准库不包含确切的功能,但该语言允许您使用一个小宏创建所需的行为。
这是我想出的:
macro_rules! all_or_nothing {
($($opt:expr),*) => {{
if false $(|| $opt.is_none())* {
None
} else {
Some(($($opt.unwrap(),)*))
}
}};
}
Run Code Online (Sandbox Code Playgroud)
如果所有值都是Some,或者None任何选项都是,则您可以提供所有选项并获得一些包含解包值的元组None。
以下是有关如何使用它的简要示例:
fn main() {
let foo = Some(0);
let bar = Some(1);
let baz = Some(2);
if let Some((a, b, c)) = all_or_nothing!(foo, bar, baz) {
println!("foo: {}; bar: {}; baz: {}", a, b, c);
} else {
panic!("Something was `None`!");
}
}
Run Code Online (Sandbox Code Playgroud)
这是宏的完整测试套件:Rust Playground
我的第一个倾向是做一些类似于swizard's answer 的事情,但将其包装在一个特征中以使链接更清洁。它也更简单一些,不需要额外的函数调用。
它确实有增加元组嵌套的缺点。
fn foo_a() -> Option<u8> {
println!("foo_a() invoked");
Some(1)
}
fn foo_b() -> Option<u8> {
println!("foo_b() invoked");
None
}
fn foo_c() -> Option<u8> {
println!("foo_c() invoked");
Some(3)
}
trait Thing<T> {
fn thing<F, U>(self, f: F) -> Option<(T, U)> where F: FnOnce() -> Option<U>;
}
impl<T> Thing<T> for Option<T> {
fn thing<F, U>(self, f: F) -> Option<(T, U)>
where F: FnOnce() -> Option<U>
{
self.and_then(|a| f().map(|b| (a, b)))
}
}
fn main() {
let x = foo_a()
.thing(foo_b)
.thing(foo_c);
match x {
Some(((a, b), c)) => println!("matched: a = {}, b = {}, c = {}", a, b, c),
None => println!("nothing matched"),
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
332 次 |
| 最近记录: |