Reputation: 1150
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
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