Chechy Levas
Chechy Levas

Reputation: 2312

Is my understanding of static trait bounds correct?

I am using the specs ECS library and I have the following type

trait TradeableResource{}

#[derive(Component)]
struct MarketMaker<T: TradeableResource + std::marker::Send + std::marker::Sync + 'static>{
    lot_size:T
}

This does not compile without the 'static constraint. I was initially concerned that this would mean that all values of this struct will have to live for the entire life of the program, but looking around, it seems the concern is invalid. Those links clearly deal with the topic but I feel they don't use language that results in a clear mental model for me. So I'd like to make my own statement about the topic, and you tell me if I am correct.

My statement

By using the 'static constraint, any type that fills the place of T must either

  1. Consist entirely of owned values, or
  2. If it contains referenced values, those must live as long as the lifetime of the program.

So the following specific case would not require anything to live the entire life of the program

#[derive(Component)]
struct Food(f64);
impl TradeableResource for Food{}

fn main() {
    let mut world = World::new();
    world.register::<MarketMaker<Food>>();

    world.create_entity().with(MarketMaker { lot_size: Food(4.0)}).build();
}

Because the type Food contains only owned values, no references.

Have I got that right?

Upvotes: 4

Views: 311

Answers (1)

Kitsu
Kitsu

Reputation: 3445

TLDR: yes, you got it correctly.

Indeed 'static term is a lit bit overloaded. It can be used as a lifetime specifier, e.g:

const T: &'static str = "static string here";

fn handle_static<T>(t: &'static T) { .. }

and as the type bound:

trait T: 'static { .. }

fn handle_owned<T>(t: T)
where T: 'static { .. }

These are fairly different cases and yours example is similar to the second one. Your statements are correct and the following example illustrates it (playground):

struct X<'a> {
    borrowed_str: &'a str,
}

let base_str = "".to_string();
// X'es lifetime bounded by base_str
let borrows = X {
    borrowed_str: base_str.as_str(),
};
let borrows_static = X { borrowed_str: "" };

fn f<T>(t: T) where T: 'static {}

// the following line fails to compile
// f(borrowed);

f(borrows_static); // though, with 'static lifetime works
f(base_str); // owned, also works fine

I also suggest you to look at amazing Common Rust Lifetime Misconceptions post if you want a structured guide to that or similar misconceptions.

Upvotes: 5

Related Questions