创建由通用 NewType 索引的通用结构

Creating a Generic Struct Indexed by a Generic NewType

我想创建一个使用通用新类型进行索引的通用结构。理想情况下,它看起来像这样:

use std::marker::PhantomData;

struct Foo<I, T> {
    bar: Vec<T>,
    _marker: PhantomData<I>,
}

impl <I, T> Foo<I, T> {
    fn new(v: Vec<T>) -> Foo<I, T> {
        Foo {
            bar: v,
            _marker: PhantomData,
        }
    }
    fn get(&self, index: &I) -> &T {
        // let index: usize = index.0; // I want to use this line.
        let index = 0; // This line is incorrect, but compiles.
        &self.bar[index]
    }
}

通用的新类型保证是usize,像这样:

pub struct Baz(pub usize);
pub struct Qux(pub usize);

这会编译并正确执行类型检查。

fn main() {
    let index_b = Baz(1);
    let index_q = Qux(1);
    let data: Foo<Baz, i32> = Foo::new(vec![1,2,3]);
    assert_eq!(*data.get(&index_b), 2);

    // Type Checking Violation - Does not compile.
    // assert_eq!(*data.get(&index_q), 2);
}

但是请注意,get() 函数不正确。您如何告诉编译器 I 是一个 usize,以便 get() 函数是正确的?

你需要使用某种特质。没有现有的约束来验证 I 实际上是 SomeType(T) 来知道 index.0 是有效的。

我的直接想法是在您的新类型上实现 Into

#[derive(Copy, Clone)]
pub struct Baz(pub usize);

impl Into<usize> for Baz {
    fn into(self) -> usize {
        self.0
    }
}

然后您将按值将 index 传递给 get:

fn get(&self, index: I) -> &T
where
    I: Into<usize>
{
    &self.bar[index.into()]
}

其他选项是 DerefAsRef 或者创建您自己的 FooIndex 特征可能有意义。


对于AsRef

fn get(&self, index: &I) -> &T
where
    I: AsRef<usize>
{
    &self.bar[*index.as_ref()]
}

Deref

fn get(&self, index: &I) -> &T
where
    I: Deref<Target=usize>
{
    &self.bar[**index]
}