有没有一种方法可以在Option中拆分变量而不必使用if语句?

时间:2018-11-21 22:57:50

标签: rust ownership

我希望下面的代码能正常工作,但是由于map()拥有Option的所有权,并且似乎没有clone()的{​​{1}}函数,因此以下内容无法编译。

Option
fn main() {
    struct ItemA {
        a: String,
        b: String,
    }
    let foo = Some(ItemA {
        a: "A String".to_owned(),
        b: "B String".to_owned(),
    });
    // OR
    // let foo = None;

    let opA: Option<String> = foo.map(|c| c.a);
    let opB: Option<String> = foo.map(|c| c.b);
}

如果error[E0382]: use of moved value: `foo` --> src/main.rs:15:31 | 14 | let opA: Option<String> = foo.map(|c| c.a); | --- value moved here 15 | let opB: Option<String> = foo.map(|c| c.b); | ^^^ value used here after move | = note: move occurs because `foo` has type `std::option::Option<main::ItemA>`, which does not implement the `Copy` trait 可以拥有opA的所有权(这样就不必克隆字符串),并且ItemA.a可以拥有opB的所有权会很好

是否可以这样做,而不必使用if语句来检查ItemA.bOption还是Some,展开并单独包装。

2 个答案:

答案 0 :(得分:1)

您可以使用map_or_else

let (opA, opB) = foo.map_or_else(
    || (None, None),
    |c| (Some(c.a), Some(c.b))
);

如果fooNone,则调用第一个函数,并返回两个None。如果fooSome,则调用第二个函数,并将成员拆分为一个元组。

当然,与简单的match相比,这并不能真正为您节省很多,并且可能会很难遵循。

let (opA, opB) = match foo {
    None => (None, None),
    Some(c) => (Some(c.a), Some(c.b))
};

顺便说一句,Option确实实现了Clone,但是它要求所包含的类型实现Clone

答案 1 :(得分:-1)

  

[T]这里似乎不是clone() [...]

Option函数

如果内部类型也实现clone,那是错误的there is。因此,在您的情况下,只需将#[derive(Clone)]添加到您的struct ItemA中即可。

接下来,您可以使用as_ref创建一个Option<&T>,然后使用map

let op_a = foo.as_ref().map(|c| &c.a);
let op_b = foo.as_ref().map(|c| &c.b);

println!("{:?}", op_a);
println!("{:?}", op_b);