具有通用特征的结构也是通用特征

Struct with a generic trait which is also a generic trait

在 Rust 1.15 中,我创建了一个特征来抽象读取和解析文件格式。我正在尝试创建一个内部具有此通用特征的结构。

我有这个特质:

use std::io::Read;

trait MyReader<R: Read> {
    fn new(R) -> Self;
    fn into_inner(self) -> R;

    fn get_next(&mut self) -> Option<u32>;
    fn do_thingie(&mut self);
}

我想创建一个结构,它引用了实现它的东西。

struct MyIterThing<'a, T: MyReader<R>+'a> {
    inner: &'a mut T,
}

出现以下错误:

error[E0412]: type name `R` is undefined or not in scope
  --> <anon>:11:36
   |
11 | struct MyIterThing<'a, T: MyReader<R>+'a> {
   |                                    ^ undefined or not in scope
   |
   = help: no candidates by the name of `R` found in your project; maybe you misspelled the name or forgot to import an external crate?

T: MyReader+'a,我得到错误:"error[E0243]: wrong number of type arguments: expected 1, found 0"T: MyReader<R: Read>+'a 给出了一个低级语法错误,它不期望那里有 :

这也行不通:

error[E0392]: parameter `R` is never used
  --> <anon>:11:24
   |
11 | struct MyIterThing<'a, R: Read, T: MyReader<R>+'a> {
   |                        ^ unused type parameter
   |
   = help: consider removing `R` or using a marker such as `std::marker::PhantomData`

如何创建我的 MyIterThing 结构?

错误消息建议您使用标记,例如 PhantomData。你可以这样做:

use std::marker::PhantomData;

struct MyIterThing<'a, R: Read, T: MyReader<R> + 'a> {
    inner: &'a mut T,
    marker: PhantomData<R>,
}

PhantomData 的实例的运行时成本为零,因此使用它比仅创建类型 R.

的字段更好

另一个解决方案是使用关联类型而不是类型参数:

trait MyReader {
    type Source: Read;

    fn new(Self::Source) -> Self;
    fn into_inner(self) -> Self::Source;

    fn get_next(&mut self) -> Option<u32>;
    fn do_thingie(&mut self);
}

struct MyIterThing<'a, T: MyReader + 'a> {
    inner: &'a mut T,
}

这有点不够灵活,因为每个 MyReader 的实现只能选择一个 Source,但这可能就足够了,具体取决于您的需要。

您可能不需要类型参数,您需要一个关联类型:

use std::io::Read;

trait MyReader {
    type R: Read;

    fn new(Self::R) -> Self;
    fn into_inner(self) -> Self::R;

    fn get_next(&mut self) -> Option<u32>;
    fn do_thingie(&mut self);
}

struct MyIterThing<'a, T>
    where T: MyReader + 'a
{
    inner: &'a mut T,
}

fn main() {}

另请参阅: