How to make impl AsRef<SomeTrait> for SomeStruct


#1
trait A {}

struct B;

impl A for B {}

impl AsRef<A> for B { 
    fn as_ref(&self) -> &A {
        self
    }   
}

It outputs error

error: method `as_ref` has an incompatible type for trait:
 expected bound lifetime parameter ,
    found concrete lifetime [E0053]

#2

Like-a so:

trait A {}

struct B;

impl A for B {}

impl AsRef<A + 'static> for B { 
    fn as_ref(&self) -> &(A + 'static) {
        self
    }   
}

The issue is that object types have an (often invisible) lifetime attached to them. This lifetime is inferred from context if it isn’t specified, which leads to the above error: the context of A for AsRef<A> and &A are different, so they get different inferred lifetimes.

Specifically, the code you wrote actually means this:

impl AsRef<A + 'static> for B { 
    fn as_ref<'a>(&'a self) -> &(A + 'a) {
        self
    }   
}

A + 'static and A + 'a are obviously not the same type, so of course it doesn’t compile. I just made both explicitly 'static.


#3

Thanks. This works

impl<'a> AsRef<A + 'a> for B {
    fn as_ref(&self) -> &(A + 'a) {
        self
    }   
}

fn foo<X: AsRef<A>>(x: X) {
}

fn main() {
    let b = B;
    foo(&b);
    foo(b);
}

#4

I don’t think that alternative is saying anything useful… B is 'static, so of course you can pick any arbitrary narrower lifetime. Unless I’m missing something (which I could be), that’s introducing an arbitrary lifetime parameter for no reason.


#5

How to write impl to return &'a (A + 'a) from &'a B


#6

You can’t. At least, not directly.

impl<'a> AsRef<A + 'a> for &'a B {
    fn as_ref(&self) -> &(A + 'a) {
        *self
    }
}

Maybe; haven’t tested, have to run. :slight_smile:


#7

Why do you want to impl AsRef<Trait>?


#8

I was curious about using AsRef, but with another type.