【问题标题】:Is there a way of extracting a value from a &mut enum when the old one is discarded? [duplicate]当旧的枚举被丢弃时,有没有办法从 &mut 枚举中提取值? [复制]
【发布时间】:2018-06-02 04:33:59
【问题描述】:

我想从模式匹配的可变引用中提取一个值并丢弃旧的。

这是我想出的一个最小的例子:

fn main() {
    #[derive(Debug)]
    enum D<A> {
        E1(A),
        E2(A, A),
    };

    trait Zero<A> {
        fn zero() -> A;
    }

    impl<A> D<A> {
        pub fn push2(&mut self, e: A) {
            match self {
                D::E1(e1) => {
                    *self = D::E2(*e1, e);
                }
                _ => unimplemented!(),
            }
        }

        pub fn push(&mut self, e: A)
        where
            A: Zero<A>,
        {
            match self {
                D::E1(e1) => {
                    let mut r = A::zero();
                    std::mem::swap(&mut r, e1);
                    *self = D::E2(e, r);
                }
                _ => unimplemented!(),
            };
        }
    }

    impl Zero<i32> for i32 {
        fn zero() -> i32 {
            0
        }
    }

    let mut d = D::E1(10);
    d.push(11);

    println!("{:?}", d);
}

playground

push2 失败:

error[E0507]: cannot move out of borrowed content
  --> src/main.rs:17:39
   |
17 |                         *self = D::E2(*e1, e);
   |                                       ^^^ cannot move out of borrowed content

我想在不需要 Copy 特征的情况下实现这一点,因为我在里面有一些盒装类型,理想情况下希望消除对虚拟变量 (A::zero()) 的需求。

【问题讨论】:

  • 有人建议我使用 std::mem::replace 而不是 std::mem::swap ,这让事情变得不那么冗长,但它仍然是实现结果的丑陋方式。跨度>

标签: reference rust mutable


【解决方案1】:

如果我理解您的代码,A 将是一个数字,因为它实现了Zero。数值在 Rust 中实现 Copy,因此您可以利用它来发挥自己的优势:

pub fn push(&mut self, e: A)
where
    A: Zero<A> + Copy,
{
    match self {
        D::E1(e1) => *self = D::E2(e, *e1),
        _ => unimplemented!(),
    };
}

如果不想绑定Copy,可以按照建议使用std::mem::replace

pub fn push(&mut self, e: A)
where
    A: Zero<A>,
{
    use std::mem::replace;
    match self {
        D::E1(e1) => *self = D::E2(e, replace(e1, A::zero())),
        _ => unimplemented!(),
    };
}

这是惯用的做法。

需要虚拟元素,因为你不能这样做:

D::E1(e1) => *self = D::E2(e, *e1),

原因是编译器先对参数求值,*e1 试图取得借用数据的所有权,但这是被禁止的。

【讨论】:

  • A 不一定是数字,它有一个零作为您可以获得的类型的一般元素,因为要使其工作,它需要在我试图获得的结构内交换一些东西中的元素。我正在寻找一种不需要 Copy 特征和虚拟元素(如果存在)的解决方案。
  • @jsmithc9 你不能那样做。我编辑解释了原因。
  • 感谢您的详细说明。
猜你喜欢
  • 2010-09-14
  • 1970-01-01
  • 1970-01-01
  • 2015-03-17
  • 1970-01-01
  • 2013-05-31
  • 1970-01-01
  • 1970-01-01
  • 2012-12-28
相关资源
最近更新 更多