I would like how to store a trait member in a struct the most idiomatic / best way.
I suppose Box<dyn Trait + 'static> is one way of doing it. But 'static doesn't seem, unless proven wrong, to be the best way of doing / writing it. Is there another way ?
Unfortunately, there doesn't seem to be a lot of resources on the net concerning this specific subject.
Hoping I was clear enough, thank you very much in advance for any help.
'static is the implied lifetime in your case, i.e. it can be elided:
I don't see why storing a Box<dyn Trait> would be unidiomatic. If you want to introduce a generic lifetime for your trait object, you'd have to propagate it to your struct definition, e.g.:
Though I would reach for a T: Trait generic parameter before I’d use dyn. Basically a stronger version of a lifetime generic, since T can have a lifetime, and if you implement Trait for Box<dyn Trait + 'a>, then users of the struct haven’t lost any flexibility (unless you genuinely needed dyn to implement most of the struct’s methods).
dyn is needed when you want to store multiple different types of implementations of Trait in the same value of the struct, and it might be good to use when the struct is cold / rarely used and you don’t want to increase the size of the executable by monomorphizing the struct. (Since dyn does come with costs to speed, in exchange for potentially reducing binary size.)
If you do want to use dyn, then yeah I agree with + 'static until needed otherwise.
Box<dyn Trait> is equivalent to Box<dyn Trait + 'static> in the sense that the former elides the 'static lifetime requirement, whereas the latter explicitly annotates the 'static lifetime requirement of the trait object. Both still require the trait object to be 'static though. That's what I wanted to say with the first part of my previous post:
I actually wonder when would you ever want to store a Box<dyn Trait + 'a> (instead of Box<dyn Trait + 'static> or &'a [mut] dyn Trait.)
Keep in mind that Box<dyn Trait + 'static> does not mean the box will live forever. It only means you can choose to keep it forever, but you still can drop it anytime.
Well, the difference between Box<dyn Trait + 'a> and &'a [mut] dyn Trait is ownership. If you need to say move the erased implementor up the stack, &dyn Trait won't do the job. And somone else may have made that choice for you by returning such a Box<_> (e.g. async_trait).
Given structs Implementor and Holder, and trait Demo implemented by Implementor, I would start with something like
struct Holder {
foo: Implementor,
}
if Holder should own the instance of Implementor, or
struct Holder<'i> {
foo: &'i Implementor,
}
if it should borrow it. The Demo trait isn't relevant to the struct's definition.
If Holder then needs to own or borrow an instance of any type that implements Demo, and not just Holder, then genericize:
struct Holder<T> {
foo: T,
}
(The lack of a T: Demo constraint is deliberate. The struct definition itself doesn't use the trait in any way, even if specific impl blocks or fns might. The constraint belongs with those items.)
Boxed trait objects are useful primarily if you need dynamic dispatch, which usually comes up when holding a heterogenous collection of values that occupy different types in the same field. There are a few other use cases for them, but they're generally not the place to start when designing something.