Maybe I forgot something. I have been "away from Rust" for a few weeks.
I browsed the source code of the Error trait and saw this:
impl Error + 'static {
/// Returns true if the boxed type is the same as `T`
#[stable(feature = "error_downcast", since = "1.3.0")]
#[inline]
pub fn is<T: Error + 'static>(&self) -> bool {
// Get TypeId of the type this function is instantiated with
let t = TypeId::of::<T>();
// Get TypeId of the type in the trait object
let boxed = self.type_id();
// Compare both TypeIds on equality
t == boxed
}
...
I am particularly interested in the impl Error + 'static
here. Error
is trait. How can I impl
a trait?
1 Like
I was confused over it as well Confusion about impls without for
In Rust, pure T
denotes a trait object type.
1 Like
Thank you.
So that implements methods for the trait object. In the case Error + 'static
that means methods on Box<Error>
. Am I right?
Also, isn't the 'static
bound inferred if I don't specify it for a trait object? So impl Error + 'static
is actually the same as impl Error
?
Yep. Or on &Error
.
Also, isn’t the 'static bound inferred if I don’t specify it for a trait object? So impl Error + 'static is actually the same as impl Error?
Not sure about this one. I think Box<Error>
is a special case of lifetime elision.
I think Box<Trait>
is implicitly Box<Trait + 'static>
. I'd imagine Box<Error>
is no different.
My guess about that is that impl Error + 'static
is a leftover from before default trait bounds were defined, but I'm not certain either.
I don't want to transform this into a grokking-lifetime-issue but I created an example and I don't really understand the result:
trait Foo {
}
impl Foo {
fn lol(&self) { println!("Hello, world"); }
}
impl Foo for Bar {}
#[derive(Debug)]
struct Bar {
v: i32,
}
fn main() {
let b = Bar { v: 100 };
let o: &Foo = &b;
o.lol();
}
fn does_not_work(o: &Foo) {
o.lol();
}
With the function does_not_work(o: &Foo)
I get my expected result. The method lol()
requires &'static Foo
. It does not work for an arbitrary lifetime, because the impl Foo
mandates 'static
. But why does the &Foo
in the main
function work? Is o
an &'static Foo
there? Is this some kind of static promotion behind the scenes?
You absolutely should - you and others can benefit.
The reason is because Trait + 'static
means the type implementing the trait must have no references or only 'static references - it doesn't mean the lifetime of a reference to the Trait object itself has to be 'static.
Your Bar
struct has no references, so it satisfies Trait + 'static
when turned into a Foo trait object. That's why main
works.
Your does_not_work
function says it takes &Foo
, which is essentially &'elided_lifetime(Foo + 'elided_lifetime)
, but it needs 'static to call lol. Two ways around this:
- Use
impl<'a> Foo + 'a {...}
to allow lol to be called for a trait object with a generic lifetime.
- Change does_not_work param to be
&(Foo + 'static)
2 Likes
Ah, yes. Trait + 'a
concerns the actual erased type of the trait object. Damn it. I actually knew that! Thanks for the great explanation though.