解开枚举变量并返回拥有的值或引用

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

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

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!(),
        }
    }
}

我的问题是:有没有一种方法可以将这些四种方法简化为两种(每个变体一个)并自动优雅地处理拥有的与参考的案例?

以下是我目前的想法:

  1. 我知道有诸如

    AsRef
    Borrow
    之类的特征,旨在灵活处理各种所有权情况,但我不知道如何将它们直接应用于上述方法。

  2. 一个或多或少明显的解决方案是只保留

    _ref
    方法,并在需要所有权时让调用者
    clone()
    输出。我认为如果然后将
    e.unwrap_a()
    替换为
    e.unwrap_a_ref().clone()
    ,则
    e
    将在调用后由借用检查器自动释放,因为之后不会使用它(否则
    e.unwrap_a()
    将无法编译),因此内存使用量基本上是切换到
    _ref
    方法不会重复。它是否正确?无论如何,对
    clone()
    的调用在调用方来说稍微有点不方便,而且它确实涉及以
    unwrap_a
    不需要的方式复制数据。

  3. 第三种选择是只保留

    _ref
    方法,并在
    A: Deref
    定义中添加
    B: Deref
    AorB
    。这与 2 非常相似,只是调用者可以免于调用
    clone()
    (据我所知)。这种方法的一个小问题是
    A
    B
    在实践中将是我自己的类型,如果可能的话,我宁愿避免为它们实现
    Deref
    ,因为这可能是一个微妙的特征。

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

rust enums borrow-checker
1个回答
0
投票

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()

© www.soinside.com 2019 - 2024. All rights reserved.