如何在具有不同类型变体的枚举上实现索引?

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

我正在尝试在我的枚举上实现

Index
,以便我可以在为自定义类型实现切片之后获取它的切片(具有切片内部值的相同变体的枚举)。但是因为我的枚举有不同类型的变体,所以我无法让它工作:

pub enum GlkArray<'a> {
    U8(&'a mut [u8]),
    U32(&'a mut [u32]),
}

impl<'a, Idx> Index<Idx> for GlkArray<'a>
where Idx: SliceIndex<[usize]>
{
    type Output = GlkArray<'a>;
    fn index(&self, index: Idx) -> &Self::Output {
        match self {
            GlkArray::U8(buf) => &GlkArray::U8(&mut buf[index]),
            GlkArray::U32(buf) => &GlkArray::U32(&mut buf[index]),
        }
    }
}

这会导致这些错误:

error[E0277]: the type `[u8]` cannot be indexed by `Idx`
   --> remglk/src/glkapi/arrays.rs:117:53
    |
117 |             GlkArray::U8(buf) => &GlkArray::U8(&buf[index]),
    |                                                     ^^^^^ slice indices are of type `usize` or ranges of `usize`
    |
    = note: required for `[u8]` to implement `Index<Idx>`
help: consider further restricting this bound
    |
112 | where Idx: SliceIndex<[usize]> + std::slice::SliceIndex<[u8]>
    |                                ++++++++++++++++++++++++++++++

error[E0277]: the type `[u32]` cannot be indexed by `Idx`
   --> remglk/src/glkapi/arrays.rs:118:55
    |
118 |             GlkArray::U32(buf) => &GlkArray::U32(&buf[index]),
    |                                                       ^^^^^ slice indices are of type `usize` or ranges of `usize`
    |
    = note: required for `[u32]` to implement `Index<Idx>`
help: consider further restricting this bound
    |
112 | where Idx: SliceIndex<[usize]> + std::slice::SliceIndex<[u32]>
    |                                +++++++++++++++++++++++++++++++

我有点理解

SliceIndex
希望在具体类型上定义,但我不确定在这种情况下该怎么做。是的,您不知道枚举从外部有什么变体,但它返回另一个封装的枚举,所以我希望没关系。

有什么想法需要如何定义

Idx
,或者我可以做什么的其他建议吗?

rust enums slice traits
1个回答
0
投票

不幸的是,您无法为此类型实现

Index
,因为它需要从
&mut
引用后面生成新的
&
引用,这是不可能的。

即使无法正确实现

Index
,仍然可以通过恐慌的
IndexMut
实现来实现
Index
,但由于生命周期和所有权问题,
IndexMut
也是不可能的。当您可变地重新借用切片时,它必须生成具有新生命周期的切片:

let mut x = [1, 2, 3];
// We'll say this reference has lifetime 'a
let slice = &mut x[..];
// This one has a new lifetime that's distinct from 'a
let slice2 = &mut slice[1..];

这意味着您无法从

GlkArray<'a>
返回
IndexMut::index_mut
。并且该特征的编写方式使得无法指定
GlkArray
的工作寿命。

此外,您无法返回对临时值的引用。这意味着返回

&mut GlkArray
不起作用,因为您必须在函数内创建一个新的
GlkArray
。这也适用于
Index

有一种方法可以解决这两个问题,那就是修改原始的

GlkArray
并返回对其的引用。但这作为索引的副作用可能是不可接受的。

相反,您可以编写自己的索引函数。您将无法使用索引运算符

[_]
,但它可以正常工作。

impl GlkArray<'_> {
    // The return of this function cannot be Self
    pub fn get_mut<'a, I>(&'a mut self, index: I) -> Option<GlkArray<'a>>
    where
        I: SliceIndex<[u8], Output = [u8]> + SliceIndex<[u32], Output = [u32]>,
    {
        match self {
            Self::U8(slice) => slice.get_mut(index).map(GlkArray::U8),
            Self::U32(slice) => slice.get_mut(index).map(GlkArray::U32),
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.