user2393256
user2393256

Reputation: 1150

Cannot satisfy `'static` lifetime requirement

I am trying to create an app with yew. I have a list of players and i want to toggle their state from active to inactive but i struggle with object lifetime. rustc tells me that the self in my view function needs 'static lifetime requirement but i don't know how to achieve this. How can i satisfy this lifetime requirement?

error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement

pub struct App {
    state: State,
}

pub struct State {
    pub players: Vec<Player>,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Player {
    pub name: String,
    pub score: usize,
    pub is_active: bool,
}

impl Component for App {
//... Omitted some boilerplate code for create and update
    fn view(&self, ctx: &Context<Self>) -> Html {
        // This gives us a component's "`Scope`" which allows us to send messages, etc to the component.
        let link = ctx.link();
        html! {
            <div>
                <button onclick={link.callback(|_| Msg::AddOne)}>{ "+1" }</button>

                <div id="players">
                {
                    self.state.players.iter().map(|p| {
                        
                        html!{
                        <div  key={p.name.as_str()}>
                        <input
                        type="checkbox"
                        class="toggle"
                        checked={p.is_active}
                        onclick={link.callback(move |_| Msg::Toggle(p.name))}
                    />
                        { format!("Hello, I'am {}!",p.name) }</div>
                    
                    }
                    }).collect::<Html>()
                }
                </div>
            </div>
        }
    }
}

Full diagnostic message:

error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
   --> src/main.rs:69:40
    |
60  |     fn view(&self, ctx: &Context<Self>) -> Html {
    |             ----- this data with an anonymous lifetime `'_`...
...
69  |                     self.state.players.iter().map(|p| {
    |                     ------------------ ^^^^
    |                     |
    |                     ...is used here...
...
77  |                         onclick={link.callback(move |_| Msg::Toggle(p.name))}
    |                                       -------- ...and is required to live as long as `'static` here
    |
note: `'static` lifetime requirement introduced by this bound
   --> /Users/benny.gaechter/.cargo/registry/src/github.com-1ecc6299db9ec823/yew-0.20.0/src/html/component/scope.rs:144:26
    |
144 |         F: Fn(IN) -> M + 'static,
    |                          ^^^^^^^

Upvotes: 0

Views: 312

Answers (1)

user2722968
user2722968

Reputation: 16475

As it says in the error message: The argument given to .callback() needs to be some Fn(IN) -> M + 'static, that is, a function that takes some IN as an argument, returns some M as a result, and as a whole is 'static (has no lifetimes shorter than 'static).

A plain function pointer is 'static, and so are closures that capture context no shorter than 'static. But the closure move |_| Msg::Toggle(p.name) captures p.name, where p comes from self.state.players, and self in self.state.players comes from fn view(&self, ...). The argument &self to view() is not 'static, and this is what the compiler complains about: The only way to make the closure passed to callback() 'static is for view() to be fn view(&'static self, ...).

An fn view(&'static self, ...) is probably not what you want to do or can do, but the compiler doesn't know that.

What you need to do is make the closure move |_| Msg::Toggle(p.name) 'static by disentangling it from the locally bound p. It may be enough to .clone() p.name and move the clone into the closure. As the clone is an owned String which has no lifetimes shorter than 'static, the closure itself becomes 'static, satisfying the requirement of .callback(). This, however, would mean that Player::name could change independently of what the callback has. If that is a possibility in your code, use a Rc/Arc and .clone() that; same argument: As the Rc/Arc owned by the closure is 'static, the closure itself becomes 'static.

Upvotes: 3

Related Questions