Пожизненная проблема с чертой Any - PullRequest
0 голосов
/ 03 февраля 2019

У меня возникла пожизненная проблема с маленькой игрой.Приведенный ниже код представляет собой очень упрощенную версию цикла обновления.Мне нужна изменяемая ссылка на контейнер, чтобы получить ссылки на другие игровые объекты или создать новые или вызвать функциональность.

По этой причине мне нужна черта Any, чтобы можно было привести черту к структуре.поэтому в свойстве GameObj я добавил метод as_any, но это привело к пожизненной проблеме.

use std::any::Any;

trait GameObj<'a> {
    fn as_any<'b>(&'b self) -> &'b (dyn Any + 'a);
    fn update(&mut self, cont: &mut container);
}

struct object<'a> {
    content: &'a String,
}

impl<'a> GameObj<'a> for object<'a> {
    fn as_any<'b>(&'b self) -> &'b (dyn Any + 'a) {
        return self;
    }

    fn update(&mut self, cont: &mut container) {
        let val = cont.get_obj().unwrap();
        let any = val.as_any();
    }
}

struct container<'a> {
    data: Vec<Box<dyn GameObj<'a> + 'a>>,
}
impl<'a> container<'a> {
    fn get_obj<'b>(&'b self) -> Option<&'b Box<dyn GameObj<'a> + 'a>> {
        return Some(&self.data[0]);
    }
}

pub fn main() {
    let a = String::from("hallo");
    let b = String::from("asdf");
    {
        let abc = object { content: &a };
        let def = object { content: &b };
        let mut cont = container { data: Vec::new() };
        cont.data.push(Box::new(abc));
        cont.data.push(Box::new(def));

        loop {
            for i in 0..cont.data.len() {
                let mut obj = cont.data.remove(0);
                obj.update(&mut cont);
                cont.data.insert(i, obj);
            }
        }
    }
}

детская площадка

Когда я пытаюсьпостроить код, это приводит к следующему сообщению об ошибке.Если я закомментирую / удаляю let any = val.as_any(); в функции update, она прекрасно компилируется.

error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
  --> src/main.rs:18:24
   |
18 |         let val = cont.get_obj().unwrap();
   |                        ^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #3 defined on the method body at 17:5...
  --> src/main.rs:17:5
   |
17 | /     fn update(&mut self, cont: &mut container) {
18 | |         let val = cont.get_obj().unwrap();
19 | |         let any = val.as_any();
20 | |     }
   | |_____^
   = note: ...so that the types are compatible:
           expected &container<'_>
              found &container<'_>
   = note: but, the lifetime must be valid for the static lifetime...
note: ...so that the declared lifetime parameter bounds are satisfied
  --> src/main.rs:19:23
   |
19 |         let any = val.as_any();
   |                       ^^^^^^

Как я могу сделать это без использования 'static, или почему это невозможно?

1 Ответ

0 голосов
/ 04 февраля 2019

Any является объявленным trait Any: 'static и может хранить только 'static типов .Таким образом, чтобы сделать dyn Any + 'a правильно сформированным типом, ваш метод as_any получил неявную границу 'a: 'static, что привело к появившейся вами ошибке времени жизни.

Если бы не это ограничение, вы быбыть в состоянии нарушить безопасность, введя тип 'a в Any и выбрать тип 'static, потому что TypeId не может определить разницу - время жизни стирается во время компиляции.См. обсуждение RFC 1849 для получения дополнительной информации.

Вам следует более тщательно продумать, почему вы хотите использовать Any.Это почти никогда не то, что вы на самом деле хотите.Возможно, что-то простое, как enum тип всех различных типов объектов, которые вы, возможно, захотите сохранить, лучше удовлетворит ваш вариант использования?

Если вы действительно хотите использовать Any,тогда вам нужно будет найти способ сделать ваши типы 'static.Rc (или Arc, если речь идет о нитях) часто бывает полезно для этой цели;например, вы могли бы иметь object магазин Rc<String> (или лучше, Rc<str>) вместо &'a String.

...