我有一个签名,看起来像这样(没有必要指定生命周期参数'a
):
fn equip_slot<'a, I: Join>(
log: &'a mut WriteExpect<GameLog>,
entities: &'a Read<EntitiesRes>,
backpack: &'a mut WriteStorage<InBackpack>,
items: I,
equipped_items: &'a mut WriteStorage<Equipped>,
names: &'a ReadStorage<Name>,
new_equip: Equipped,
new_equip_ent: Entity,
) -> HashSet<(Entity, Item)>
where
I: Copy,
I::Type: IsItem,
cargo clippy
正确地指出了这个函数有太多的参数,我尝试了几种方法将这些参数分组到一个元组中,但是创建元组(甚至引用的元组)的行为似乎会造成一些困难。
例如:
type EquipData<'a, I> = (
&'a Read<'a, EntitiesRes>,
&'a mut WriteExpect<'a, GameLog>,
&'a mut WriteStorage<'a, InBackpack>,
I,
&'a mut WriteStorage<'a, Equipped>,
&'a ReadStorage<'a, Name>,
);
// ...
fn equip_slot<'a, I: Join + Copy>(
equip_data: EquipData<'a, I>,
new_equip: Equipped,
new_equip_ent: Entity,
) -> HashSet<(Entity, Item)>
where
I::Type: IsItem,
// Then at the call site, the following original line:
equip_slot(&mut log, &entities, &mut backpack, &items, &mut equipped, &names, new_equip, useitem.item);
// is changed to
equip_slot((&entities, &mut log, &mut backpack, &items, &mut equipped, &names), new_equip, useitem.item);
但是现在我得到了很多错误,特别是与生命周期有关的错误。有没有更好的方法来处理这个问题,或者我在当前的方法中做错了什么?下面是错误:
error[E0521]: borrowed data escapes outside of closure
--> src/inventory_system.rs:180:25
|
117 | mut log,
| ------- `log` declared here, outside of the closure body
...
180 | equip_slot((&entities, &mut log, &mut backpack, &items, &mut equipped, &names), new_equip, useitem.item);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: lifetime may not live long enough
--> src/inventory_system.rs:177:53
|
128 | mut equipped,
| ------------ lifetime `'2` appears in the type of `equipped`
...
148 | .for_each(|(player_entity, _player, useitem, player_name)| {
| ------------------------------------------------ lifetime `'1` represents this closure's body
...
177 | targets.first().iter().for_each(|target| {
| _____________________________________________________^
178 | | let new_equip = Equipped::new(**target, &player_equip, &equip.allowed_slots);
179 | | // TODO: warn on non-unit discard?:
180 | | equip_slot((&entities, &mut log, &mut backpack, &items, &mut equipped, &names), new_equip, useitem.item);
181 | | });
| |______________________^ closure capture requires that `'1` must outlive `'2`
|
= note: closure implements `FnMut`, so references to captured variables can't escape the closure
error[E0499]: cannot borrow `log` as mutable more than once at a time
--> src/inventory_system.rs:187:49
|
128 | mut equipped,
| ------------ lifetime `'2` appears in the type of `equipped`
...
177 | targets.first().iter().for_each(|target| {
| -------- first mutable borrow occurs here
...
180 | equip_slot((&entities, &mut log, &mut backpack, &items, &mut equipped, &names), new_equip, useitem.item);
| --------------------------------------------------------------------------------------------------------
| | |
| | first borrow occurs due to use of `log` in closure
| argument requires that `log` is borrowed for `'2`
...
187 | targets.iter().for_each(|target| {
| ^^^^^^^^ second mutable borrow occurs here
...
194 | log.entries.push(format!(
| --- second borrow occurs due to use of `log` in closure
error[E0499]: cannot borrow `log` as mutable more than once at a time
--> src/inventory_system.rs:220:29
|
128 | mut equipped,
| ------------ lifetime `'2` appears in the type of `equipped`
...
177 | targets.first().iter().for_each(|target| {
| -------- first mutable borrow occurs here
...
180 | equip_slot((&entities, &mut log, &mut backpack, &items, &mut equipped, &names), new_equip, useitem.item);
| --------------------------------------------------------------------------------------------------------
| | |
| | first borrow occurs due to use of `log` in closure
| argument requires that `log` is borrowed for `'2`
...
220 | log.entries.push(format!(
| ^^^ second mutable borrow occurs here
error[E0499]: cannot borrow `log` as mutable more than once at a time
--> src/inventory_system.rs:234:34
|
128 | mut equipped,
| ------------ lifetime `'2` appears in the type of `equipped`
...
177 | targets.first().iter().for_each(|target| {
| -------- first mutable borrow occurs here
...
180 | equip_slot((&entities, &mut log, &mut backpack, &items, &mut equipped, &names), new_equip, useitem.item);
| --------------------------------------------------------------------------------------------------------
| | |
| | first borrow occurs due to use of `log` in closure
| argument requires that `log` is borrowed for `'2`
...
234 | .map(|victim| {
| ^^^^^^^^ second mutable borrow occurs here
...
245 | log.entries.push(format!(
| --- second borrow occurs due to use of `log` in closure
error[E0597]: `log` does not live long enough
--> src/inventory_system.rs:180:53
|
148 | .for_each(|(player_entity, _player, useitem, player_name)| {
| ------------------------------------------------ value captured here
...
180 | equip_slot((&entities, &mut log, &mut backpack, &items, &mut equipped, &names), new_equip, useitem.item);
| ^^^ borrowed value does not live long enough
...
259 | }
| -
| |
| `log` dropped here while still borrowed
| borrow might be used here, when `log` is dropped and runs the destructor for type `specs::Write<'_, GameLog, PanicHandler>`
error[E0597]: `backpack` does not live long enough
--> src/inventory_system.rs:180:63
|
148 | .for_each(|(player_entity, _player, useitem, player_name)| {
| ------------------------------------------------ value captured here
...
180 | equip_slot((&entities, &mut log, &mut backpack, &items, &mut equipped, &names), new_equip, useitem.item);
| ^^^^^^^^ borrowed value does not live long enough
...
259 | }
| -
| |
| `backpack` dropped here while still borrowed
| borrow might be used here, when `equipped` is dropped and runs the destructor for type `Storage<'_, components::Equipped, FetchMut<'_, MaskedStorage<components::Equipped>>>`
|
= note: values in a scope are dropped in the opposite order they are defined
error[E0597]: `equipped` does not live long enough
--> src/inventory_system.rs:180:86
|
148 | .for_each(|(player_entity, _player, useitem, player_name)| {
| ------------------------------------------------ value captured here
...
180 | equip_slot((&entities, &mut log, &mut backpack, &items, &mut equipped, &names), new_equip, useitem.item);
| ^^^^^^^^ borrowed value does not live long enough
...
259 | }
| -
| |
| `equipped` dropped here while still borrowed
| borrow might be used here, when `equipped` is dropped and runs the destructor for type `Storage<'_, components::Equipped, FetchMut<'_, MaskedStorage<components::Equipped>>>`
error[E0597]: `names` does not live long enough
--> src/inventory_system.rs:180:97
|
148 | .for_each(|(player_entity, _player, useitem, player_name)| {
| ------------------------------------------------ value captured here
...
180 | equip_slot((&entities, &mut log, &mut backpack, &items, &mut equipped, &names), new_equip, useitem.item);
| ^^^^^ borrowed value does not live long enough
...
259 | }
| -
| |
| `names` dropped here while still borrowed
| borrow might be used here, when `log` is dropped and runs the destructor for type `specs::Write<'_, GameLog, PanicHandler>`
|
= note: values in a scope are dropped in the opposite order they are defined
error[E0382]: use of partially moved value: `equip_data`
--> src/inventory_system.rs:347:21
|
270 | let (entities, log, backpack, items, equipped_items, names) = equip_data;
| -------------- value partially moved here
...
347 | equip_data,
| ^^^^^^^^^^ value used here after partial move
|
= note: partial move occurs because `equip_data.4` has type `&mut Storage<'_, components::Equipped, FetchMut<'_, MaskedStorage<components::Equipped>>>`, which does not implement the `Copy` trait
1条答案
按热度按时间cgyqldqp1#
通过对我的问题的评论(特别是建议在任何可能的地方使用不同的生命周期参数),我能够提出一个解决方案。
请注意,在我将一些参数提取到元组中之前,
equip_slot
函数的生命周期参数被推断出来。特别是,内部存储值的生命周期参数没有被指定(我只是-可选地-指定了对Storage结构的引用的生命周期参数)。但是当我们声明一个类型时,我们必须指定生命周期参数:这表明内部存储的值必须有一个不同的生命周期参数(
'b
),从存储本身的引用('a
)。特别是,对于可变引用,我们必须有例如&'a mut WriteExpect<'b, GameLog>
而不是&'a mut WriteExpect<'a, GameLog>
。如果我们不这样做,那么我们会得到几个错误,但特别是:和
我们的引用值(例如
log
)可能会被删除,但我们仍然需要确保Storage值本身比引用log
更长寿,因为它是通过闭包捕获的(并且可能在闭包外部使用)。因此我们需要通过单独的生命周期参数'a
和'b
进行解耦。在我们的例子中,这就是我们需要的所有分辨率。现在,我们可以回到
equip_slot
自动推断生命周期参数: