假设我有一个具有两个变体的枚举,每个变体都包含不同类型的单个值 - 并且枚举在这两种类型上是通用的:
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!(),
}
}
}
我的问题是:有没有一种方法可以将这些四种方法简化为两种(每个变体一个)并自动优雅地处理拥有的与参考的案例?
以下是我目前的想法:
我知道有诸如
AsRef
和 Borrow
之类的特征,旨在灵活处理各种所有权情况,但我不知道如何将它们直接应用于上述方法。
一个或多或少明显的解决方案是只保留
_ref
方法,并在需要所有权时让调用者 clone()
输出。我认为如果然后将 e.unwrap_a()
替换为 e.unwrap_a_ref().clone()
,则 e
将在调用后由借用检查器自动释放,因为之后不会使用它(否则 e.unwrap_a()
将无法编译),因此内存使用量基本上是切换到 _ref
方法不会重复。它是否正确?无论如何,对 clone()
的调用在调用方来说稍微有点不方便,而且它确实涉及以 unwrap_a
不需要的方式复制数据。
第三种选择是只保留
_ref
方法,并在 A: Deref
定义中添加 B: Deref
和 AorB
。这与 2 非常相似,只是调用者可以免于调用 clone()
(据我所知)。这种方法的一个小问题是 A
和 B
在实践中将是我自己的类型,如果可能的话,我宁愿避免为它们实现 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()
。