Введите соответствие BTreeSet внутри кортежа в Rust - PullRequest
0 голосов
/ 08 октября 2018

У меня есть код следующим образом (часть большой библиотеки).Компилятор говорит мне, что кортеж не реализует черту, но у меня есть реализация как для кортежа, так и для одного элемента этого кортежа.И он работает с другими типами кортежей.

Почему кортеж (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 голосов
/ 08 октября 2018

В цепочке реализации есть пробел:

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

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

Первый impl предоставляет Render для ссылки на BTreeSet, тогда как второй обеспечиваетреализация для кортежа ссылки на что-то, что реализует 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();
    }
}

Рабочая площадка

См. Также:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...