假设我有一个具有两个变量的枚举,每个变量都包含不同类型的单个值--并且枚举在这两种类型上是泛型的:

enum AorB<A, B> {
    A(A),
    B(B),
}

在我的代码库中经常会发生这样的事情,即我知道我收到的是哪个变量,并且我需要解开已知类型的内部值.我知道这可能会引起一些关于设计的问题,但让我们把这些放在一边.在任何情况下,我都想编写方便的展开方法,以避免每次出现这种情况时都要match次.

这种情况基本上有两种形式:我有一个指向AorB<A, B>的指针,我想得到一个指向内部值的指针;或者当我很乐意消费整个AorB<A, B>对象时,我想得到内部值的所有权.这就产生了四种方法:

impl<A, B> AorB<A, B> {
    fn unwrap_a(self) -> A {
        match self {
            AorB::A(a) => a,
            _ => panic!(),
        }
    }

    fn unwrap_b(self) -> B {
        match self {
            AorB::B(b) => b,
            _ => panic!(),
        }
    }

    fn unwrap_a_ref(&self) -> &A {
        match self {
            AorB::A(a) => a,
            _ => panic!(),
        }
    }

    fn unwrap_b_ref(&self) -> &B {
        match self {
            AorB::B(b) => b,
            _ => panic!(),
        }
    }
}

My question is:有没有办法将这四个方法简化为两个(每个变体一个),并自动优雅地处理所拥有的 case 与参考 case ?

以下是我目前的 idea :

  1. 我知道有一些特性,比如AsRefBorrow,可以灵活地处理各种所有权情况,但我看不出如何将它们直接应用于上述方法.

  2. 一种或多或少显而易见的解决方案是只保留_ref个方法,只要需要所有权就让调用者clone()输出.我认为如果将e.unwrap_a()替换为e.unwrap_a_ref().clone(),e将在调用后由borrow 判断器自动释放,因为它不会在以后使用(否则e.unwrap_a()将不会编译),因此切换到_ref方法基本上不会重复使用内存.这样对吗?在任何情况下,对clone()的调用在调用者端都有一点不方便,而且它确实涉及到以unwrap_a不需要的方式复制数据.

  3. 第三种 Select 是只保留_ref个方法,并在AorB定义中添加A: DerefB: Deref.这与2非常相似,只是呼叫者不用拨打clone()(据我所知).这种方法的一个小问题是,AB在实践中将是我自己的类型,如果可能的话,我宁愿避免为它们实现Deref,因为这可能是一个微妙的特征.

有没有比上面的2或3更好的方法来实现我所寻求的方法简化?

推荐答案

Option也有类似的问题,它通过引入一个方法as_ref来解决这个问题,这个方法允许从&Option<T>Option<&T>.我认为它在这里也很好用:

impl<A, B> AorB<A, B> {
    fn as_ref(&self) -> AorB<&A, &B> {
        match self {
            AorB::A(a) => AorB::A(a),
            AorB::B(b) => AorB::B(b),
        }
    }
}

然后,当您需要避免消费时,只需插入对as_ref的呼叫:

a_or_b.as_ref().unwrap_a();

而不是直接拨打.unwrap_a().

Rust相关问答推荐

trait 中self 的显式生命周期似乎导致E0499无法在循环中多次borrow * emits 器作为可变的

通用池类型xsx

是否有可能同时避免不兼容的不透明类型和代码重复?

如何为 struct 字段设置新值并在Ruust中的可变方法中返回旧值

有没有一种惯用的方法来判断VEC中是否存在变体?

当对VEC;U8>;使用serde_json时,Base64编码是保护空间的好方法吗?

如何实现Serde::Ser::Error的调试

我们能确定Rust会优化掉Clone()吗?如果它会立即掉落?

如果变量本身不是None,如何返回;如果没有,则返回None&Quot;?

如何在AVX2中对齐/旋转256位向量?

如何初始化选项<;T>;数组Rust 了?

为什么 tokio 在以奇怪的方式调用时只运行 n 个任务中的 n-1 个?

RUST 中的读写器锁定模式

在 Rust 中,为什么 10 个字符的字符串的 size_of_val() 返回 24 个字节?

如何使用 Bincode 在 Rust 中序列化 Enum,同时保留 Enum 判别式而不是索引?

sha256 摘要仅适用于 &*

缺失serde的字段无法设置为默认值

特征中定义的类型与一般定义的类型之间的区别

如何在 Rust 的泛型函​​数中同时使用非拥有迭代器和消费迭代器?

在 Rust 中组合特征的不同方法是否等效?