在Rust中的元组中匹配BTreeSet的类型

时间:2018-10-08 16:13:37

标签: rust

我有以下代码(属于较大库的一部分)。编译器告诉我,一个元组没有实现特征,但是我既有一个元组的实现,又有该元组的一个元素的实现。它可以与另一种元组一起使用。

为什么元组(BTreeSet<Annotation>)在这里不匹配?

use std::collections::BTreeSet;

pub struct Axiom {}
pub struct Annotation {}

pub struct AnnotatedAxiom {
    pub axiom: Axiom,
    pub annotation: BTreeSet<Annotation>,
}

trait Render {
    /// Render a entity to Write
    fn render(&self);
}

impl<'a, T: Render> Render for &'a BTreeSet<T> {
    fn render(&self) {}
}

impl<'a, A: Render> Render for (&'a A,) {
    fn render(&self) {
        (&self.0).render();
    }
}

/// The types in `Render` are too long to type.
macro_rules! render {
    ($type:ty, $self:ident,
     $body:tt) => {

        impl Render for $type {
            fn render(& $self)
                $body
        }
    }
}

render!{
    Annotation, self,
    {
    }
}
render!{
    Axiom, self,
    {
    }
}

render!{
    AnnotatedAxiom, self,
    {
        // Axiom implements Render
        (&self.axiom).render();

        // Annotation implements Render
        (&self.annotation).render();

        // A 1-element tuple of Axiom implements Render
        (&self.axiom,).render();

        // A 1-element tuple of Annotation does!?
        (&self.annotation,).render();

    }
}

fn main() {}

Playground

error[E0599]: no method named `render` found for type `(&std::collections::BTreeSet<Annotation>,)` in the current scope
  --> src/main.rs:62:29
   |
62 |         (&self.annotation,).render();
   |                             ^^^^^^
   |
   = note: the method `render` exists but the following trait bounds were not satisfied:
           `(&std::collections::BTreeSet<Annotation>,) : Render`
   = help: items from traits can only be used if the trait is implemented and in scope
   = note: the following trait defines an item `render`, perhaps you need to implement it:
           candidate #1: `Render`

1 个答案:

答案 0 :(得分:3)

实施链中存在空白:

impl<'a, T: Render> Render for &'a BTreeSet<T> {
    // ....
}

impl<'a, A: Render> Render for (&'a A,) {
    // ...
}

第一个implRender提供引用BTreeSet,而第二个{<1>}提供了 reference元组的实现 Render。由于BTreeSet本身未实现Render(仅对其进行引用!),因此编译器将拒绝工作。

在这种情况下,从引用中抽象出来更符合人体工程学,因为Render似乎适合于对另一个Render可能值的任何引用。对所有引用&T实施此特征,其中T: Render

impl<'a, T> Render for &'a T
where
    T: Render,
{
    fn render(&self) {
        (**self).render();
    }
}

由于以下原因,其余实现变得稍微简单了:

impl<T> Render for BTreeSet<T>
where
    T: Render,
{
    fn render(&self) {}
}

impl<A> Render for (A,)
where
    A: Render,
{
    fn render(&self) {
        (&self.0).render();
    }
}

Working Playground

另请参阅: