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,
| ^^^^^^^
As it says in the error message: The argument given to
.callback()needs to be someFn(IN) -> M + 'static, that is, a function that takes someINas an argument, returns someMas 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 closuremove |_| Msg::Toggle(p.name)capturesp.name, wherepcomes fromself.state.players, andselfinself.state.playerscomes fromfn view(&self, ...). The argument&selftoview()is not'static, and this is what the compiler complains about: The only way to make the closure passed tocallback()'staticis forview()to befn 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)'staticby disentangling it from the locally boundp. It may be enough to.clone()p.nameandmovethe clone into the closure. As the clone is an ownedStringwhich has no lifetimes shorter than'static, the closure itself becomes'static, satisfying the requirement of.callback(). This, however, would mean thatPlayer::namecould change independently of what the callback has. If that is a possibility in your code, use aRc/Arcand.clone()that; same argument: As theRc/Arcowned by the closure is'static, the closure itself becomes'static.