2015-03-06 5 views
3

У меня есть основной (и, вероятно, глупый) вопрос собственности. Я пытаюсь создать вектор &str от String значений, обернутых внутри Some(String). Я использую промежуточные переменный для хранения извлеченной/развернутой String и, кажется, мне нужно определить этот промежуточный переменную перед вектором для того, чтобы удовлетворить Заимствование проверки:Почему переменная область зависит от порядка определения?

Рабочего код:

fn main() { 
    let a = Some("a".to_string()); 

    let mut val = String::new(); 
    let mut v = Vec::<&str>::new(); 

    if a.is_some() { 
     val = a.unwrap(); 
     v.push(&val[..]); 
    } 
    println!("{:?}", val); 
} 

Non рабочий код:

fn main() { 
    let a = Some("a".to_string()); 

    let mut v = Vec::<&str>::new(); 
    let mut val = String::new(); 

    if a.is_some() { 
     val = a.unwrap(); 
     v.push(&val[..]); 
    } 
    println!("{:?}", val); 
} 

И компилятор ошибки:

<anon>:9:17: 9:20 error: `val` does not live long enough 
<anon>:9   v.push(&val[..]); 
         ^~~ 
<anon>:4:35: 12:2 note: reference must be valid for the block suffix following statement 1 at 4:34... 
<anon>:4  let mut v = Vec::<&str>::new(); 
<anon>:5  let mut val = String::new(); 
<anon>:6 
<anon>:7  if a.is_some() { 
<anon>:8   val = a.unwrap(); 
<anon>:9   v.push(&val[..]); 
     ... 
<anon>:5:32: 12:2 note: ...but borrowed value is only valid for the block suffix following statement 2 at 5:31 
<anon>:5  let mut val = String::new(); 
<anon>:6 
<anon>:7  if a.is_some() { 
<anon>:8   val = a.unwrap(); 
<anon>:9   v.push(&val[..]); 
<anon>:10  } 
     ... 
error: aborting due to previous error 
playpen: application terminated with error code 101 

The playpen code

вопрос: почему я должен определить переменную val перед вектором v? Как я вижу, область val та же, что и область v, или я что-то не хватает?

ответ

3

Привязки отбрасываются в обратном порядке объявления, то есть самая последняя заявленная вещь уничтожается в первую очередь. В частности, в коде, который не работает, деструктор val запускается до деструктора v. Без тщательного рассмотрения того, что делает Vec<&str>::drop(), это небезопасно: он может, например, попытаться просмотреть содержимое содержащихся в нем строк, несмотря на то, что String, из которого они получены, уже уничтожен.

Vec на самом деле не делает этого, но другие законные типы делают что-то в этом направлении. Раньше было невозможно безопасно реализовать Drop для типов, которые содержат сроки жизни/заимствованные указатели. A relatively recent change делает это безопасным, вводя эти дополнительные ограничения.

Обратите внимание, что если вы объявите let v, val; или let val, v;, а затем назначить, два привязок сделать имеют тот же срок службы, так что это не невозможно иметь две переменные одного и того же срока.

+0

Спасибо. Определение обеих переменных в одной строке делает работу независимой от порядка, например. например: let (mut v, mut val) = (Vec :: <&str> :: new(), String :: new()); ' – maximi

+0

Теперь возникает интересный вопрос: в каком порядке находятся' v' и ' val' уничтожаются, когда они объявляются сразу? Потому что вам все равно понадобится «val» для уничтожения после 'v', делает ли компилятор правильный порядок? –

+0

@ MatthieuM. Хороший вопрос. Это изменение состоит из двух частей: один - это правила кавычек (что линейный тип * строго * переживает все ссылки внутри него), а другой - 'let x; пусть у; ... 'анализируется как' let x; {пусть у; {...}} '. Последний является технически синтаксическим сахаром, он упрощает выполнение ограничений с первой части. Мое лучшее предположение заключается в том, что требование «структурно переживает» не относится к Vec, возможно, потому, что оно все еще использует '# [unsafe_destructor]' или потому, что у него нет параметра продолжительности жизни? Тогда оба с одинаковым временем жизни будут кошерными. – delnan