Укажите, что время жизни аргумента длится для вызова функции - PullRequest
0 голосов
/ 05 октября 2018

У меня есть черта с функцией, которая берет ссылку на итератор:

#[derive(Clone)]
struct Dog {
    name: &'static str,
}

trait DogListAction<'a, I>
where
    I: Iterator<Item = &'a Dog>,
{
    fn on_dog_list(&mut self, dog_list: I);
}

struct DogListActionExample {}

impl<'a, I> DogListAction<'a, I> for DogListActionExample
where
    I: Iterator<Item = &'a Dog>,
{
    fn on_dog_list(&mut self, dog_list: I) {
        for dog in dog_list {
            println!("{}", dog.name);
        }
    }
}

fn main() {
    let dogs = vec![Dog { name: "Pluto" }, Dog { name: "Lilly" }];
    let mut action_example = DogListActionExample {};
    let mut dog_list_actions: Vec<Box<DogListAction<_>>> = vec![Box::new(action_example)];
    loop {
        let dog_clone = dogs.clone();
        for dog_list_action in &mut dog_list_actions {
            dog_list_action.on_dog_list(dog_clone.iter());
        }
    }
}

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

Она не берет никаких ссылок на элементы,поэтому нет необходимости, чтобы он длился дольше, чем вызов функции.

Из-за моего ограниченного понимания жизней, я пока не знаю, как это выразить.Вызов этой функции вызывает ошибку компиляции:

error[E0597]: `dog_clone` does not live long enough
  --> src/main.rs:33:41
   |
33 |             dog_list_action.on_dog_list(dog_clone.iter());
   |                                         ^^^^^^^^^ borrowed value does not live long enough
34 |         }
35 |     }
   |     - `dog_clone` dropped here while still borrowed
36 | }
   | - borrowed value needs to live until here

Я полагаю, что средство проверки заимствований считает, что на данные в dog_clone можно ссылаться после завершения функции, но это не так.

1 Ответ

0 голосов
/ 06 октября 2018

Проблема здесь в том, что код потенциально может сохранять недолговечные ссылки на dog_clone элементы в более долгоживущих dog_list_actions.Нам нужно сообщить компилятору, что мы не будем сохранять ссылки, создаваемые итератором.Это можно сделать так:

trait DogListAction {
    fn on_dog_list<'a, I>(&'a mut self, dog_list: I)
    where
        I: Iterator<Item = &'a Dog>;
}

Теперь Item могут жить в течение вызова on_dog_list.В исходном коде они должны жить дольше.

Но этот код создает другую проблему: мы больше не можем пометить черту DogListAction, поскольку она включает в себя универсальную функцию.Обычный подход здесь заключается в использовании объекта черты:

trait DogListAction {
    fn on_dog_list<'a>(&'a mut self, dog_list: Box<dyn Iterator<Item = &'a Dog> + 'a>);
}

Обратите внимание на второй 'a в Box<dyn Iterator<Item = &'a Dog> + 'a>.Rust добавляет черту 'static, связанную с объектами черт в штучной упаковке по умолчанию, и нам здесь не нужно 'static.

#[derive(Clone)]
struct Dog {
    name: &'static str,
}

trait DogListAction {
    fn on_dog_list<'a>(&'a mut self, dog_list: Box<dyn Iterator<Item = &'a Dog> + 'a>);
}

struct DogListActionExample {}

impl DogListAction for DogListActionExample {
    fn on_dog_list<'a>(&'a mut self, dog_list: Box<dyn Iterator<Item = &'a Dog> + 'a>) {
        for dog in dog_list {
            println!("{}", dog.name);
        }
    }
}

fn main() {
    let dogs = vec![Dog { name: "Pluto" }, Dog { name: "Lilly" }];
    let action_example = DogListActionExample {};
    let mut dog_list_actions: Vec<Box<DogListAction>> = vec![Box::new(action_example)];
    {
        let dogs_clone = dogs.clone();
        for dog_list_action in &mut dog_list_actions {
            dog_list_action.on_dog_list(Box::new(dogs_clone.iter()));
        }
    }
}

Playground

...