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

问题描述 投票:0回答:2

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

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
。我尝试应用我在匹配臂中看到的任何语法,但它总是告诉我类型只是
&SensitiveVector<T>
,因此访问元组字段
0
是不可能的。

我知道代码可能很糟糕。但有人能告诉我该怎么做吗?当然,我可以只使用两个向量并创建一个新的

SensitiveVector
实例,但我认为扩展
self
更有效。

感谢您的帮助并解释我缺少的语法/概念/规则。

rust match
2个回答
0
投票

问题是双重的:

  1. 您正在匹配
    (&self, &other)
    ,因此模式中的值始终是共享引用,它们不能被拥有(返回)并且不能被修改。
  2. 枚举变体不是 Rust 中的类型,并且 Rust 没有类型细化。所以
    vector @ Filled(_)
    会给你一个
    vector: SensitiveVector
    (最好的情况下,这里是一个
    &SensitiveVector
    ),你无法从枚举本身访问枚举变体的字段,所以如果你的目标是,模式匹配很大程度上是浪费的更新内容。

既然你无论如何都要按值获取

self
other
,第一个解决办法就是也匹配它们,这意味着你还需要返回在第二个和第三个臂中匹配的值,或者需要重建内容中的值:

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
      }
    }
  }
}

这并不能修复第四臂,但现在您应该将内部向量移出,合并向量,然后重新包装结果,而不是使用@模式:

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,
      (Filled(mut v), Filled(other)) => {
        v.extend(other);
        Filled(v)
      }
    }
  }
}

0
投票

数值和参考之间存在一些不匹配。 由于您似乎想要处理值(使用参数来发出新值),因此我建议您一直使用值(特别是删除 match 语句中的引用)。

一旦 match 语句解构

self
other
,这两个值就不再存在,只是解构后的成员仍然存在,那么你必须从这些成员重新创建一个枚举(而不是尝试重用
self
other
作为一个整体)。

这是您的示例,进行了一些更正。

#[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])
*/
© www.soinside.com 2019 - 2024. All rights reserved.