Скажем, у нас есть глобально доступная хеш-карта трейт-объектов, которую мы создаем с помощью lazy_static: MY_ANIMALS: Mutex<HashMap<i32, AnimalBox>>
, где type AnimalBox = Box<dyn AnimalExt+Send>
Теперь мы хотим, чтобы животные в этой глобальной хеш-карте взаимодействовали друг с другом. Например, один AnimalBox
может AnimalExt::eat(&mut self, prey: &mut AnimalBox)
другого.
Проблема в том, что наша функция eat()
требует как изменяемой ссылки на себя, так и изменяемой ссылки на молитву (потому что мы хотим, чтобы молитва AnimalExt::perish(&mut self)
была съедена.
Однако получение двух изменяемых ссылок на нашу хеш-карту вызывает ошибку WouldBlock
:
use lazy_static::lazy_static;
use std::sync::Mutex;
use std::collections::HashMap;
//type alias for our boxed animals
type AnimalBox = Box<dyn AnimalExt+Send>;
//globally accessible hashmap for keeping track of our animals throughout the scope of our application
lazy_static! {
static ref MY_ANIMALS: Mutex<HashMap<i32, AnimalBox>> = Mutex::new(HashMap::new());
}
//simple trait for our animals
trait AnimalExt{
//eat() function requires a mutable reference to another AnimalBox
fn eat(&mut self, pray: &mut AnimalBox);
fn perish(&mut self);
fn energy(&self)->i32;
fn id(&self)->i32;
}
struct Wolf{
id: i32,
energy: i32,
alive: bool,
}
impl AnimalExt for Wolf{
fn id(&self)->i32{
self.id
}
fn eat(&mut self, pray: &mut AnimalBox) {
pray.perish();
self.energy+= pray.energy()
}
fn energy(&self) ->i32 {
self.energy
}
fn perish(&mut self){
self.alive = false;
}
}
impl Wolf{
pub fn new(id: i32)->Self{
Wolf{
id: id,
energy: 50,
alive: true,
}
}
}
struct Cow{
id: i32,
energy: i32,
alive: bool,
}
impl Cow{
pub fn new(id: i32)->Self{
Cow{
id: id,
energy: 100,
alive: true,
}
}
}
impl AnimalExt for Cow{
fn id(&self)->i32{
self.id
}
fn eat(&mut self, pray: &mut AnimalBox) {
pray.perish();
self.energy+= pray.energy()
}
fn energy(&self) ->i32 {
self.energy
}
fn perish(&mut self){
self.alive = false;
}
}
fn main() {
println!("Hello, world!");
//define our animals
let cow1 = Box::new(Cow::new(1)) as AnimalBox;
let cow2 = Box::new(Cow::new(2)) as AnimalBox;
let wolf1 = Box::new(Wolf::new(3)) as AnimalBox;
let wolf2 = Box::new(Wolf::new(4)) as AnimalBox;
//insert them into the global hashmap
MY_ANIMALS.lock().unwrap().insert(cow1.id(), cow1);
MY_ANIMALS.lock().unwrap().insert(cow2.id(), cow2);
MY_ANIMALS.lock().unwrap().insert(wolf1.id(), wolf1);
MY_ANIMALS.lock().unwrap().insert(wolf2.id(), wolf2);
//getting one animal to eat() another causes a WouldBlock error
match (MY_ANIMALS.try_lock().unwrap().get_mut(&0), MY_ANIMALS.try_lock().unwrap().get_mut(&1)){
(Some(a1), Some(a2))=>{
a1.eat(a2);
}
_=>()
}
}
Есть ли хорошая работа для этого? Или нет безопасного способа сделать это с помощью хэш-карты? Я видел этот ответ на аналогичный вопрос, но предлагаемый ответ предлагает использовать RefCell
, что несовместимо с требованием черты lazy_static Send
.