Rust 在模式匹配中克隆不可克隆对象的可克隆元素

Rust 在模式匹配中克隆不可克隆对象的可克隆元素,rust,borrow-checker,Rust,Borrow Checker,我正在从事一个项目,该项目使用带有自定义枚举值的BTreeMap。此枚举无法#[导出(克隆)],因为某些变量可能包含一个不能克隆的值。我的项目大致概述如下: enum Foo { // Bar has impl Clone, Baz does not. // Both Bar and Baz are from external crates, // so I cannot impl Clone on Baz. A(Result<Vec<Bar>,

我正在从事一个项目,该项目使用带有自定义枚举值的
BTreeMap
。此
枚举
无法
#[导出(克隆)]
,因为某些变量可能包含一个不能
克隆的值。我的项目大致概述如下:

enum Foo {
    // Bar has impl Clone, Baz does not.
    // Both Bar and Baz are from external crates,
    // so I cannot impl Clone on Baz.
    A(Result<Vec<Bar>, Baz>),
    B(Bar, Qux),
    C,
}

struct Waldo {
    map: BTreeMap<Bar, Foo>,
    // Other variables...
}

理想情况下,我希望能够在离开
if let
子句之前创建
bar_vec
的克隆,这意味着不再借用
self.map
。这是可能的,还是我必须重构代码的工作方式?我已经考虑过让
analyze
返回
Foo
枚举值而不是直接将其添加到映射中的选项,并让
dou\u something
与返回值匹配,并在最后将其添加到映射中,但是我觉得我还是把这个问题发出来,看看是否可以做一些不那么痛苦的事情。

如果您可以接受使用nightly compiler,那么您可以使用非词汇生存期

#![feature(nll)]

use std::collections::BTreeMap;

#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
struct Bar;

// I cannot impl Clone on Baz
struct Baz;

enum Foo {
    A(Result<Vec<Bar>, Baz>),
    B(Bar),
    C,
}

struct Waldo {
    map: BTreeMap<Bar, Foo>,
    // Other variables...
}

impl Waldo {
    fn do_something(&mut self, data: Bar) {
        self.analyze(data.clone());
        if let Some(&Foo::A(Ok(ref bar_vec))) = self.map.get(&data) {
            let unique = bar_vec
                .iter()
                .filter(|b| !self.map.contains_key(b))
                .cloned() 
                .collect::<Vec<Bar>>();

            for new_item in unique.iter().cloned() {
                self.map.insert(new_item, Foo::C); 
            }
            for new_item in unique.into_iter() {
                self.do_something(new_item);
            }
        }
    }

    fn analyze(&mut self, data: Bar) {
        unimplemented!()
    }
}

那么Qux呢?这是可克隆的吗?最简单的方法是在上游回购中修复这一点,如果可能:)@hellow-Qux可能是可克隆的,也可能不是可克隆的,就本例而言,我认为这与此无关。主要的一点是,当内部值为
Ok
时,从
Foo::A
中提取的项目会执行
impl Clone
,但
Foo
本身不能是
Clone
d。请提供一个。您的代码包含两个与您的问题无关的错误。@red75prime我一定是因为睡眠不足。尽我所能减少我的项目。问题中的错误是什么?这或多或少是我期望的答案,不过为了理解,我确实有一个问题:在NLL示例中,如果我在
for
循环之后使用
bar_vec
做了其他事情,编译会失败吗(因为这扩展了借用的要求)?是的,借款持续到借款人最后一次使用。
#![feature(nll)]

use std::collections::BTreeMap;

#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
struct Bar;

// I cannot impl Clone on Baz
struct Baz;

enum Foo {
    A(Result<Vec<Bar>, Baz>),
    B(Bar),
    C,
}

struct Waldo {
    map: BTreeMap<Bar, Foo>,
    // Other variables...
}

impl Waldo {
    fn do_something(&mut self, data: Bar) {
        self.analyze(data.clone());
        if let Some(&Foo::A(Ok(ref bar_vec))) = self.map.get(&data) {
            let unique = bar_vec
                .iter()
                .filter(|b| !self.map.contains_key(b))
                .cloned() 
                .collect::<Vec<Bar>>();

            for new_item in unique.iter().cloned() {
                self.map.insert(new_item, Foo::C); 
            }
            for new_item in unique.into_iter() {
                self.do_something(new_item);
            }
        }
    }

    fn analyze(&mut self, data: Bar) {
        unimplemented!()
    }
}
    fn do_something(&mut self, data: Bar) {
        self.analyze(data.clone());
        // This allows to access `unique` outside the scope
        // where `self.map` is borrowed
        let unique;
        if let Some(&Foo::A(Ok(ref bar_vec))) = self.map.get(&data) {
            unique = bar_vec
                .iter()
                .filter(|b| !self.map.contains_key(b)) // &Bar, sans those in map
                .cloned() 
                .collect::<Vec<Bar>>();
        } else {
            // early return prevents the use of uninitialized `unique`
            return;
        }
        for new_item in unique.iter().cloned() {
            self.map.insert(new_item, Foo::C); 
        }
        for new_item in unique.into_iter() {
            self.do_something(new_item);
        }
    }