| Crates.io | option-chain |
| lib.rs | option-chain |
| version | 0.1.2 |
| created_at | 2025-03-22 02:12:41.666983+00 |
| updated_at | 2025-03-28 08:02:12.26605+00 |
| description | A macro for using `?` operator in functions that don't return `Option`. |
| homepage | |
| repository | https://github.com/PRO-2684/Candy-Pile |
| max_upload_size | |
| id | 1601474 |
| size | 7,285 |
A macro for using ? operator in functions that don't return Option.
macro_rules!, without any dependency - even the standard library!use option_chain::opt;
struct Test1 {
a: Option<Test2>,
}
struct Test2 {
b: Option<Test3>,
}
struct Test3 {
c: i32,
}
let v = Test1 {
a: Some(Test2 { b: Some(Test3 { c: 42 }) }),
};
let c = opt!(v.a?.b?.c);
assert_eq!(c.unwrap(), 42);
Consider the following scenario:
struct Test1 {
a: Option<Test2>,
}
struct Test2 {
b: Option<Test3>,
}
struct Test3 {
c: i32,
}
fn main() {
let v = Test1 {
a: Some(Test2 { b: Some(Test3 { c: 42 }) }),
};
// We want to get the value of the `c` field, returning `None` if any member in the "chain of fields" is `None`.
}
Essentially, we're looking for Rust-equivalent of the following JavaScript code:
const c = v?.a?.b?.c;
Usually you'd utilize the and_then and map methods:
# struct Test1 {
# a: Option<Test2>,
# }
# struct Test2 {
# b: Option<Test3>,
# }
# struct Test3 {
# c: i32,
# }
#
# fn main() {
# let v = Test1 {
# a: Some(Test2 { b: Some(Test3 { c: 42 }) }),
# };
let c = v.a.and_then(|a| a.b).map(|b| b.c);
assert_eq!(c.unwrap(), 42);
# }
Which looks quite verbose. flatten is also a good choice:
# struct Test1 {
# a: Option<Test2>,
# }
# struct Test2 {
# b: Option<Test3>,
# }
# struct Test3 {
# c: i32,
# }
#
# fn main() {
# let v = Test1 {
# a: Some(Test2 { b: Some(Test3 { c: 42 }) }),
# };
let c = v.a.map(|a| a.b).flatten().map(|b| b.c);
assert_eq!(c.unwrap(), 42);
# }
But it's still not as concise as the JavaScript code. Also, you might think of creating a helper function:
# struct Test1 {
# a: Option<Test2>,
# }
# struct Test2 {
# b: Option<Test3>,
# }
# struct Test3 {
# c: i32,
# }
#
# fn main() {
# let v = Test1 {
# a: Some(Test2 { b: Some(Test3 { c: 42 }) }),
# };
fn get_c(v: Test1) -> Option<i32> {
Some(v.a?.b?.c)
}
let c = get_c(v);
assert_eq!(c.unwrap(), 42);
# }
Which is better, but you'll need to create a function for every different chain of fields you want to access.
This is where option-chain comes in:
# use option_chain::opt;
#
# struct Test1 {
# a: Option<Test2>,
# }
# struct Test2 {
# b: Option<Test3>,
# }
# struct Test3 {
# c: i32,
# }
#
# fn main() {
# let v = Test1 {
# a: Some(Test2 { b: Some(Test3 { c: 42 }) }),
# };
let c = opt!(v.a?.b?.c);
assert_eq!(c.unwrap(), 42);
# }
It just wraps the expression in a closure which returns Option, and immediately calls it:
macro_rules! opt {
($e:expr) => {{ || -> Option<_> { Some($e) }() }};
}