fadedbee
fadedbee

Reputation: 44807

How do I state that I want a struct which contains a reference to something which implements a trait?

Editor's note: The code presented in the question compiles as-is in Rust 1.0.

I've tried:

trait Inner {}

struct Outer<'a> {
    inner: &'a Inner,
}

but the compiler complains:

   Compiling tst v0.1.0 (file:///home/chris/rust/tst)
/home/chris/rust/tst/src/main.rs:4:14: 4:19 error: explicit lifetime bound required
/home/chris/rust/tst/src/main.rs:4   inner: &'a Inner,

Upvotes: 1

Views: 4569

Answers (2)

Vladimir Matveev
Vladimir Matveev

Reputation: 128001

How do I tell Rust that I want a struct which contains a reference to something which implements a trait?

There are two ways. First, the preferred one, is to use generics:

struct Outer<'a, T> {
    inner: &'a T,
}

impl<'a, T: Inner> Outer<'a, T> {
    // ...
}

This method is the most efficient as all function calls are statically dispatched. It's also the most type-safe one, but its disadvantage is that you will have to specify the trait bound everywhere you use Outer<T> and you won't be able to hold different implementations of Inner in the same structure at different times because T must be known in advance.

Another way is to use a trait object:

struct Outer<'a> {
    inner: &'a (Inner + 'a),
}

This is what you have already tried, and the error you see is caused by not specifying the lifetime bound: that + 'a thing. You need to specify a lifetime bound because traits can be implemented for structs with lifetime parameters (like Outer), and if you box such a structure into a trait object, you need a way to specify its lifetime parameter in trait object type.

The advantage of trait objects is a fewer amount of annotations and the ability to use an arbitrary type as inner field of the same Outer value, as long it satisfies Inner bound. The downside is that you will get dynamic dispatch instead, which may be slightly less efficient. You also wouldn't be able to get back the original type of the trait object without additional machinery.

Upvotes: 6

Felipe Valdes
Felipe Valdes

Reputation: 2217

This is an example of a struct which uses a lifetime specifier.

I had to create a struct with a field that is a reference to the type SWide. This field needs to be a reference inside the struct, so I added a lifetime specifier to the struct, and also added a lifetime specifier to the impl, notice how you must use the same lifetime specifier twice in the impl line:

extern crate mysql;

use mysql::Pool;
use swide::SWide;

pub struct Context<'a> {
    pub connection_pool: Pool,
    pub cache: Option<&'a SWide>,
}
impl<'a> Context<'a> {
    pub fn new_with_cache(connection_pool: Pool, cache: Option<&'a SWide>) -> Self {
        Context {
            connection_pool: connection_pool,
            cache: cache,
        }
    }
}

Upvotes: -1

Related Questions