使用具有特征的泛型

时间:2019-08-22 06:51:21

标签: rust traits

我正在尝试实现包含通用函数的特征。但是,我无法在实现的函数中实例化一个结构。

trait Extractor {
    fn parse(&self) -> String;
}

struct BooksExtractor {}

impl Extractor for BooksExtractor {
    fn parse(&self) -> String {
        "test".to_owned()
    }
}

struct Pass<E: Extractor> {
    pub extractor: Option<E>,
    pub name: String,
    pub next_pass: Option<Box<Pass<E>>>,
}

trait Robot: Sized {
    fn get_pass<E: Extractor>(&self) -> Pass<E>;
}

struct GutenbergRobot {}

impl Robot for GutenbergRobot {
    fn get_pass<E: Extractor + ?Sized>(&self) -> Pass<E>
        where E: Extractor + Sized {
        Pass {
            extractor: Some(BooksExtractor {}),
            name: "test".to_owned(),
            next_pass: None
        }
    }
}

当尝试实例化已实现函数中的extractor结构时,编译器抱怨参数应为Pass字段的类型:

error[E0308]: mismatched types
  --> src\main.rs:33:29
   |
33 |             extractor: Some(BooksExtractor {}),
   |                             ^^^^^^^^^^^^^^^^^ expected type parameter, found struct `BooksExtractor`
   |
   = note: expected type `E`
              found type `BooksExtractor`

2 个答案:

答案 0 :(得分:2)

您的Robot::get_pass函数不应是通用的。相反,您应该使用关联的类型:

trait Robot: Sized {
    type Extractor: Extractor;
    fn get_pass(&self) -> Pass<Self::Extractor>;
}

impl Robot for GutenbergRobot {
    type Extractor = BooksExtractor;
    fn get_pass(&self) -> Pass<BooksExtractor> {
        Pass {
            extractor: Some(BooksExtractor {}),
            name: "test".to_owned(),
            next_pass: None
        }
    }
}

简而言之,当调用方可以选择函数返回的类型时,应该使用通用类型;而当 implementer 选择类型时,应该使用相关类型。

>

另请参阅this question

答案 1 :(得分:1)

您对get_pass的函数签名指定它将构造一个Pass<E>类型。这意味着它应该在Pass<E: Extractor + Sized>有效的任何地方工作。

想象一下,除了代码之外,您还具有以下结构:

struct OtherBooksExtractor {}
impl Extractor for OtherBooksExtractor {
    fn parse(&self) -> String {
        "foobar".to_owned()
    }
}

然后,您将期望以下操作基于类型:

fn bla() -> Pass<OtherBookExtractor> {
   GutenbergRobot.get_pass()
}
assert_eq!(bla.extractor.parse(), "foobar")

但是,您正在构造比Pass<E>中的通用get_pass更具体的东西:Pass<BooksExtractor>!如果允许的话,这意味着我编写的代码将无法正常工作。