У меня есть Vec
, содержащий данные персонажа, и я хочу одновременно запускать AI персонажа для каждого персонажа. Это происходит не из соображений производительности, а потому, что у каждого ИИ есть периоды восстановления, в течение которых он спит, позволяя другим ИИ работать.
ИИ разрешено изменять CharacterState
, но только тот, которому он был назначен. Поэтому теоретически каждый ИИ имеет доступ к отдельной части Vec
, и не будет множественных ссылок ни на один CharacterState
.
Однако я изо всех сил пытаюсь выразить это в ржавчине. Как мне:
Vec
на несколько изменяемых ссылок, по одной для каждого элемента.Вот что у меня есть на данный момент: Rust Playground
#[derive(Clone, Default)]
struct Actor<TState>(TState);
impl<TState> Actor<TState> {
pub fn new(initial_state: TState) -> Self {
Actor(initial_state)
}
pub async fn act(&mut self, action: &(impl Action<State = TState> + ?Sized)) {
action.execute(&mut self.0).await;
}
}
#[async_trait::async_trait]
trait Action: Send + Sync {
type State;
async fn execute(&self, state: &mut Self::State);
}
struct CharacterData {
x: i32,
y: i32
}
type CharacterActor = Actor<CharacterData>;
struct RunCharacterAction;
#[async_trait::async_trait]
impl Action for RunCharacterAction {
type State = CharacterData;
async fn execute(&self, _state: &mut Self::State) {
todo!()
}
}
struct WorldData {
characters: Vec<CharacterActor>
}
type WorldActor = Actor<WorldData>;
struct RunWorldAction;
#[async_trait::async_trait]
impl Action for RunWorldAction {
type State = WorldData;
async fn execute(&self, state: &mut Self::State) {
let tasks: Vec<_> = state.characters
.iter_mut()
.map(|character| {
tokio::spawn(async {
let action = RunCharacterAction;
character.act(&action).await;
})
}).collect();
futures::future::join_all(tasks).await;
}
}
#[tokio::main]
async fn main() {
let mut world = WorldActor::new(WorldData {
characters: vec![
CharacterActor::new(CharacterData { x: 1, y: 2 }),
CharacterActor::new(CharacterData { x: 3, y: 4 })]
});
let action = RunWorldAction;
world.act(&action).await;
}
Что приводит к следующей ошибке
error[E0521]: borrowed data escapes outside of method
--> src/main.rs:51:29
|
50 | async fn execute(&self, state: &mut Self::State) {
| ----- - lifetime `'life1` defined here
| |
| `state` is a reference that is only valid in the method body
51 | let tasks: Vec<_> = state.characters
| _____________________________^
52 | | .iter_mut()
| | ^
| | |
| |_______________________`state` escapes the method body here
| argument requires that `'life1` must outlive `'static`
For more information about this error, try `rustc --explain E0521`.
error: could not compile `playground` (bin "playground") due to 1 previous error
@BallpointBen Верно, но я не хочу потреблять Vec
, если это возможно
Это должно быть возможно с iter_mut()
. Что вы пробовали?
И join_all().
Я добавил пример игровой площадки того, что у меня есть на данный момент.
Пожалуйста, вставьте код в вопрос как Минимально воспроизводимый пример.
Поскольку вам не нужно, чтобы задачи выполнялись параллельно, вам не нужно их создавать. join_all
достаточно, чтобы опросить их все одновременно.
let tasks = state
.characters
.iter_mut()
.map(|character| async move {
let action = RunCharacterAction;
character.act(&action).await;
});
futures::future::join_all(tasks).await;
Не надо collect()
.
Вероятно, проще всего использовать
Vec
с чем-то вродеinto_iter()
, превратить каждый элемент в задачу, затем дождаться всех и собрать в другойVec
.