The trait `A` is not implemented for the type `&&#

2019-07-21 10:04发布

I’m having trouble using a generic function that takes a generic trait object as a parameter. When I try to call the function, the compiler complains “error: the trait Next is not implemented for the type &'a mut Next<Type=Type> + 'a [E0277]”. In my opinion, the Next trait is object-safe for any parameter Type, so Next should be implemented by any &Next<Type> (by my reading of Huon’s Object-Safety article); is there any way to check that it is object-safe?

Incidentally, I’m having no problem doing pretty much the same thing with an Iterator, and I don’t know how that is different.

trait Next {
    type Type;
    fn next(&mut self) -> Option<Self::Type>;
}
struct NextImpl<Type> {
    next: Option<Type>,
}
impl<Type> Next for NextImpl<Type> {
    type Type = Type;
    fn next(&mut self) -> Option<Self::Type> {
        let mut ret = None;
        std::mem::swap(&mut self.next, &mut ret);
        ret
    }
}

struct DelegatingNext<'a, Type> {
    delegate: &'a mut Next<Type=Type>,
}
impl<'a, Type> Next for DelegatingNext<'a, Type> {
    type Type = Type;
    fn next(&mut self) -> Option<Self::Type> {
        self.delegate.next()

        // error: the trait `Next` is not implemented for the type `&'a mut Next<Type=Type> + 'a` [E0277]
        // Next::next(&mut self.delegate)
        // ^~~~~~~~~~

        // error: the trait `Next` is not implemented for the type `&'a mut Next<Type=Type> + 'a` [E0277]
        // if (true) {
        // next_next1(&mut self.delegate)
        // ^~~~~~~~~~

        // error: the trait `Next` is not implemented for the type `&'a mut Next<Type=Type> + 'a` [E0277]
        // next_next2(&mut self.delegate)
        //            ^~~~~~~~~~~~~~~~~~
    }
}
fn next_next1<'a, NextType: Next + ?Sized>(m: &'a mut NextType) -> Option<NextType::Type> {
    m.next()
}
fn next_next2<'a, Type>(m: &'a mut Next<Type=Type>) -> Option<Type> {
    m.next()
}
struct DelegatingIterator<'b, T> {
    iter: &'b mut Iterator<Item=T>,
}
impl<'b, T> DelegatingIterator<'b, T> {
    fn next(&mut self) -> Option<T> {
        let iter: &mut Iterator<Item=T> = self.iter;

        iterator_next1(iter)

        // error: the trait `core::marker::Sized` is not implemented for the type `core::iter::Iterator<Item=T>` [E0277]
        // note: `core::iter::Iterator<Item=T>` does not have a constant size known at compile-time
        // iterator_next2(iter)
        // ^~~~~~~~~~~~~~

        // OK
        // iterator_next3(iter)

        // OK
        // iterator_next4(iter)
    }
}
fn iterator_next1<'a, T>(iter: &mut Iterator<Item=T>) -> Option<T> {
    iter.next()
}
fn iterator_next2<It: Iterator>(iter: &mut It) -> Option<It::Item> {
    iter.next()
}
fn iterator_next3<It: Iterator + ?Sized>(iter: &mut It) -> Option<It::Item> {
    iter.next()
}
fn iterator_next4<'a, Item>(iter: &mut Iterator<Item=Item>) -> Option<Item> {
    iter.next()
}

fn main() {
    let mut m = NextImpl {next: Some("hi")};
    let mut delegating_model = DelegatingNext {delegate: &mut m};
    assert!(Some("hi") == delegating_model.next());
    let v: Vec<i32> = vec!(1, 2, 3);
    let mut iter = v.iter();
    assert_eq!(Some(&1), (DelegatingIterator {iter: &mut iter }).next());
}

标签: rust
1条回答
ゆ 、 Hurt°
2楼-- · 2019-07-21 10:56

I think you are adding an extra layer of indirection. The method call self.delegate.next() desugars into Next::next(self.delegate) in this case - no automatic referencing (mutable or otherwise) is needed.

The error message is confusing because you have two levels of reference. Your trait is written:

trait Next {
    fn next(&mut self)
}

Which means that you always have to pass in a &mut Foo. However, you were taking a second mutable reference, making the argument type &mut &mut NextImpl<Type>. The first &mut is matched by the function parameter, but then the rest of the type needs to implement Next. However, &mut NextImpl<Type> does not implement that trait, only NextImpl<Type> does!

Your Sized problem is very similar. The function is defined as

fn iterator_next2<It: Iterator>(iter: &mut It) -> Option<It::Item>

That is, it expects a mutable reference to some concrete type that implements Iterator. Your call passes a &mut Iterator - a trait object. A trait object is a reference to something without a known size, it is only known to implement the methods of the trait. Since you don't care about the size of the thing being referred to, the correct option is to declare that, as you did:

fn iterator_next3<It: Iterator + ?Sized>(iter: &mut It) -> Option<It::Item> {
    iter.next()
}

This is super confusing, so let me know if I need to attempt to explain it differently.

查看更多
登录 后发表回答