2016-10-07 6 views
1

У меня есть тест на прогрессе, который не компилируется:Декларирование жизни на тестовой функции

#[test] 
fn node_cost_dequeue() { 
    let mut queue: BinaryHeap<&NodeCost> = BinaryHeap::new(); 
    let cost_1: NodeCost = NodeCost::new(1, 50, 0); 
    let cost_2: NodeCost = NodeCost::new(2, 30, 0); 
    let cost_3: NodeCost = NodeCost::new(3, 80, 0); 
    queue.push(&cost_1); 
    queue.push(&cost_2); 
    queue.push(&cost_3); 
    assert_eq!(2, (*queue.pop().unwrap()).id); 
} 

Результатов в error: cost_1 does not live long enough

С дополнительной информацией, что «позаимствовали стоимость упала до того заемщика».

Поэтому я пытаюсь добавить явные аннотации для жизни.

#[test] 
fn node_cost_dequeue() { 
    let mut queue: BinaryHeap<&'a NodeCost> = BinaryHeap::new(); 
    let cost_1: NodeCost<'a> = NodeCost::new(1, 50, 0); 
    let cost_2: NodeCost<'a> = NodeCost::new(2, 30, 0); 
    let cost_3: NodeCost<'a> = NodeCost::new(3, 80, 0); 
    queue.push(&cost_1); 
    queue.push(&cost_2); 
    queue.push(&cost_3); 
    assert_eq!(2, (*queue.pop().unwrap()).id); 
} 

Это результат use of undeclared lifetime name 'a.

Таким образом, я пытаюсь объявить его функции

fn node_cost_dequeue<'a>() ->() { 

Но это приводит к error: functions used as tests must have signature fn() ->()

Я на правильном пути? Как объявить эту жизнь?

+0

В этом вопросе вы можете найти несколько аналогичный случай (хотя со скрытой утечкой из-за того же времени жизни обоих объектов) [http://stackoverflow.com/q/39827244/1870153). – ljedrz

+0

См. Также [Как инициализировать переменную со временем жизни?] (Http://stackoverflow.com/questions/28108689/how-to-initialize-a-variable-with-a-lifetime) => вы не можете, всю жизнь * аннотация * не обеспечивает срок службы, она просто документирует ее. –

ответ

6

Что это говорит вам, ..

Все обрывается в обратном порядке .. cost_1 будет отброшен перед тем queue .. потому что объявленное после queue. Итак, queue имеет ссылку на cost_1 и потому что значения теперь отбрасываются в конце метода. queue теперь имеет ссылку на ... ничего? cost_1 был отброшен, а queue по-прежнему «жив» - хотя его тоже нужно отбросить.

Чтобы быть ясным, последовательность событий имеет значение, поскольку экземпляр BinaryHeap хранит ссылки. Он не владеет его содержимым.

Последовательность событий будет:

  • Объявите BinaryHeap экземпляр, который хранит ссылки.
  • Объявляет cost_1, cost_2 и cost_3, чьи ссылки будет вставлены в BinaryHeap.
  • Добавить ссылки в BinaryHeap.
  • Выполнить утверждение.
  • Капля cost_3.
  • Капля cost_2.
  • Капля cost_1.
  • Какое значение имеют ссылки BinaryHeap? Элементы отбрасываются.
  • Капля BinaryHeap.

Жирным шрифтом в приведенном выше списке является то, от чего компилятор защищает вас. Потенциально недействительные указатели.

Легко исправить ..чтобы изменить порядок декларирования, что любые ссылки на cost_1 переживет queue:

let cost_1: NodeCost = NodeCost::new(1, 50, 0); 
let cost_2: NodeCost = NodeCost::new(2, 30, 0); 
let cost_3: NodeCost = NodeCost::new(3, 80, 0); 
let mut queue: BinaryHeap<&NodeCost> = BinaryHeap::new(); 

Вот рабочий example on the playground

Порядок событий теперь будет:

  • Объявить cost_1, cost_2 и cost_3, чьи ссылки будут вставлены в BinaryHeap.
  • Заявка BinaryHeap экземпляр, который хранит ссылки.
  • Добавить ссылки в BinaryHeap.
  • Выполнить утверждение.
  • Капля BinaryHeap. Ссылки могут исчезнуть, потому что элементы, которые они ссылаются, все еще живы.
  • Капля cost_3.
  • Капля cost_2.
  • Капля cost_1.