我正在尝试写一个特性,这将允许我"解包"多个嵌套Option<Option<...<T>>>>到单个,Option<T>以更好地使用我正在使用的API.我正在尝试创建一个通用解决方案,但我无法弄清楚如何使其工作.
这是我的许多尝试之一:
trait UnwrapOption<T> {
fn unwrap_opt(self) -> Option<T>;
}
impl<T> UnwrapOption<T> for Option<T> {
fn unwrap_opt(self) -> Option<T> {
self
}
}
impl<T> UnwrapOption<T> for Option<Option<T>> {
fn unwrap_opt(self) -> Option<T> {
match self {
Some(e) => e.unwrap_opt(),
None => None,
}
}
}
fn main() {
let x = Some(Some(Some(1)));
println!("{:?}", x.unwrap_opt());
}
Run Code Online (Sandbox Code Playgroud)
正如另一个答案所示,我并没有将嵌套选项弄平,而是提倡你永远不要创建一个Option<Option<T>>你需要首先扁平化的东西.在我见过的大多数情况下,这是因为Option::map当他们应该使用时会有人误用Option::and_then:
fn main() {
let input = user_input();
let a = input.map(add1);
// a is Option<Option<i32>>
let b = input.and_then(add1);
// a is Option<i32>
}
fn user_input() -> Option<i32> {
Some(10)
}
fn add1(a: i32) -> Option<i32> {
Some(a + 1)
}
Run Code Online (Sandbox Code Playgroud)
请记住,Rust是一种静态类型的语言; 你将永远知道嵌套的确切程度.
我用自动特征(optin_builtin_traits)解决了这个问题,但是我不确定这是否是最好的方法:
#![feature(optin_builtin_traits)]
trait IsOption {}
impl<T> IsOption for Option<T> {}
auto trait IsSingleOption {}
impl<T> !IsSingleOption for Option<Option<T>> {}
trait UnwrapOption {
type Inner;
fn unwrap_opt(self) -> Option<Self::Inner>;
}
impl<T> UnwrapOption for Option<T>
where
Self: IsSingleOption,
{
type Inner = T;
fn unwrap_opt(self) -> Option<Self::Inner> {
self
}
}
impl<T> UnwrapOption for Option<T>
where
T: IsOption + UnwrapOption,
{
type Inner = <T as UnwrapOption>::Inner;
fn unwrap_opt(self) -> Option<Self::Inner> {
match self {
Some(e) => e.unwrap_opt(),
None => None,
}
}
}
fn main() {
let x = Some(Some(Some(1)));
println!("{:?}", x.unwrap_opt());
let x = Some(1);
println!("{:?}", x.unwrap_opt());
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
456 次 |
| 最近记录: |