如何在Rust中的匹配表达式上保留匹配臂中的枚举变量

ekqde3dh  于 12个月前  发布在  其他
关注(0)|答案(2)|浏览(105)

我认为这个问题最好用一个例子来描述:

enum SensitiveVector<T> {
  Empty,
  Filled(Vec<T>),
}

impl<T> for SensitiveVector<T> {
  pub fn append(mut self, other: Self) -> Self {
    match (&self, &other) {
      (Empty, Empty) => Empty,
      (Empty, Filled(_)) => other,
      (Filled(_), Empty) => self,
      (mut vector @ Filled(_), Filled(other_items) => {
        vector.0.append(other_items);
        vector
      }
    }
  }
}

我试图提高效率,而不是简单地克隆向量或类似的,但重用内存(希望)有效。无论如何,比赛表达式的第四个手臂是我的问题。我只是不知道如何将other示例的向量项附加到self,如果这个手臂匹配的话。我尝试应用我在match arm中看到的任何语法,但它总是告诉我类型只是&SensitiveVector<T>,所以访问元组字段0是不可能的。
我知道代码可能很可怕。但是谁能告诉我怎么做这样的事情?当然,我可以只使用这两个向量并创建一个新的SensitiveVector示例,但我认为扩展self更有效。
感谢您的任何帮助,并解释我的语法/概念/规则,我错过了。

qhhrdooz

qhhrdooz1#

在值和引用之间存在一些不匹配。既然你似乎想要处理值(使用参数来发出新值),我建议你一直使用值(特别是删除match语句中的引用)。
一旦match语句破坏了selfother,这两个值就不再存在了,只是破坏后的成员仍然存在,那么你必须从这些成员重新创建一个枚举(而不是试图重用整个selfother)。
这是你的例子,有几个修正。

#[derive(Debug)]
enum SensitiveVector<T> {
    Empty,
    Filled(Vec<T>),
}

impl<T> SensitiveVector<T> {
    fn append(
        self,
        other: Self,
    ) -> Self {
        match (self, other) {
            (Self::Empty, Self::Empty) => Self::Empty,
            (Self::Empty, Self::Filled(other_items)) => {
                Self::Filled(other_items)
            }
            (Self::Filled(items), Self::Empty) => Self::Filled(items),
            (Self::Filled(mut items), Self::Filled(mut other_items)) => {
                items.append(&mut other_items);
                Self::Filled(items)
            }
        }
    }
}

fn main() {
    {
        let sv1 = SensitiveVector::<i32>::Empty;
        let sv2 = SensitiveVector::<i32>::Empty;
        println!("empty and empty: {:?}", sv1.append(sv2));
    }
    {
        let sv1 = SensitiveVector::<i32>::Empty;
        let sv2 = SensitiveVector::Filled(vec![1, 2, 3]);
        println!("empty and filled: {:?}", sv1.append(sv2));
    }
    {
        let sv1 = SensitiveVector::Filled(vec![1, 2, 3]);
        let sv2 = SensitiveVector::<i32>::Empty;
        println!("filled and empty: {:?}", sv1.append(sv2));
    }
    {
        let sv1 = SensitiveVector::Filled(vec![1, 2, 3]);
        let sv2 = SensitiveVector::Filled(vec![4, 5, 6]);
        println!("filled and filled: {:?}", sv1.append(sv2));
    }
}
/*
empty and empty: Empty
empty and filled: Filled([1, 2, 3])
filled and empty: Filled([1, 2, 3])
filled and filled: Filled([1, 2, 3, 4, 5, 6])
*/
fkvaft9z

fkvaft9z2#

问题是双重的:
1.你在(&self, &other)上匹配,所以模式中的值总是 * 共享引用 *,它们不能被拥有(返回),也不能被修改。
1.枚举变体不是rust中的类型,并且rust没有类型改进。所以vector @ Filled(_)将给予一个vector: SensitiveVector(在这里,它最多是一个&SensitiveVector),你不能从枚举本身访问枚举变量的字段,所以如果你的目标是更新内容,那么模式匹配在很大程度上是浪费的。
因为你无论如何都要通过值来获取selfother,所以第一个修复方法是也匹配它们,这意味着你还需要返回你在第二和第三个臂中匹配的值,或者需要从内容中重构值:

enum SensitiveVector<T> {
  Empty,
  Filled(Vec<T>),
}
use SensitiveVector::*;

impl<T> SensitiveVector<T> {
  pub fn append(mut self, other: Self) -> Self {
    match (self, other) {
      (Empty, Empty) => Empty,
      (Empty, v @ Filled(_)) => v,
      (v @ Filled(_), Empty) => v,
      (mut vector @ Filled(_), Filled(other_items)) => {
        vector.0.append(other_items);
        vector
      }
    }
  }
}

这并没有修复第四个手臂,但是现在你不应该使用@-模式,你应该把内部的向量移出来,合并向量,然后重新 Package 结果:

enum SensitiveVector<T> {
  Empty,
  Filled(Vec<T>),
}
use SensitiveVector::*;

impl<T> SensitiveVector<T> {
  pub fn append(self, other: Self) -> Self {
    match (self, other) {
      (Empty, Empty) => Empty,
      (Empty, v @ Filled(_)) => v,
      (v @ Filled(_), Empty) => v,
      (Filled(mut v), Filled(ref mut other)) => {
        v.append(other);
        Filled(v)
      }
    }
  }
}

相关问题