Arc<T> requiring a lifetime for T. Why?

I have following code snippet:

use std::sync::{Arc};


pub trait Test {
    
}

pub struct TransformVisitor {
    tester: Arc<dyn Test>
}

pub fn foo(tester: Arc<impl Test>) -> TransformVisitor {
    TransformVisitor {tester: tester}
}

The build fails with

error[E0310]: the parameter type `impl Test` may not live long enough
  --> src/lib.rs:13:31
   |
13 |     TransformVisitor {tester: tester}
   |                               ^^^^^^ ...so that the type `impl Test` will meet its required lifetime bounds
   |
help: consider adding an explicit lifetime bound...
   |
12 | pub fn foo(tester: Arc<impl Test + 'static>) -> TransformVisitor {

Any hints? Also hints to relevant documentation/articles are welcome.

See the code in the Rust playground Rust Playground

Arc<T> requiring a lifetime for T. Why?

Because everything requires a lifetime, basically. It's just that explicit lifetimes can often be elided when concrete types are known (e.g. a String is known to be 'static and a struct containing a &'a T is known to be 'a). However, when you've got yourself a generic or a trait object, its underlying concrete type is not known to the compiler locally, so you have to ensure that it is valid lifetime-wise by adding the lifetime bounds explicitly.

Thanks for your quick rely :slight_smile: I understand that this is the case for references. So lifetimes are also needed for smarter pointers like Arc?

No, it's not that Arc itself requires the lifetime. It's that the lifetime bound of every type must be known. Lifetime bounds of the form T: 'a assert that values of the type may be put behind a reference of type &'a T (i.e. they are valid as long as 'a). This has nothing to do with whether they are currently wrapped in any sort of pointer or not – it's about the potential of creating a normal reference to them.

1 Like

Whenever you write Arc<dyn Trait + 'a>, then this has the following meaning:

This Arc can contain any value that implements the Trait trait, and has no lifetime annotations shorter than 'a.

When you create the Arc<dyn Trait>, then this is short-hand for Arc<dyn Trait + 'static>, so the compiler must ensure that the actual type has no lifetime annotations shorter than 'static.

However, generics are different than dyn Trait (impl Trait is short-hand for generics). When you use generics, they come with no restrictions on lifetimes annotated on the value, so an impl Test could be any type that implements Test, including types with very short lifetime annotations on them. By adding + 'static, you are saying "and this type must not have lifetime annotations shorter than 'static".

4 Likes

Thanks @alice @H2CO3 for your answers. I have adjusted the code and it works.

use std::sync::{Arc};

pub trait Test { }

pub struct TransformVisitor <'a>  {
    tester: Arc<dyn Test + 'a>
}

pub fn foo<'a>(tester: Arc<impl Test + 'a>) -> TransformVisitor<'a> {
    TransformVisitor {tester: tester}
}