2014-09-27 1 views
7

Я учусь ржавчина, и я написал следующий код для чтения массива целых чисел от stdin:Использования `let` связывания для увеличения срока службы значения

use std::io; 
fn main() { 
    for line in io::stdin().lines() { 
     let xs:Vec<int> = line.unwrap().as_slice().trim().split(' ') 
       .map(|s|from_str::<int>(s).unwrap()).collect(); 
     println!("{}", xs); 
    } 
} 

Это работало отлично, однако, я чувствовал, let xs линия была немного долго, поэтому я разделил его на две части:

fn main() { 
    for line in io::stdin().lines() { 
     let ss = line.unwrap().as_slice().trim().split(' '); 
     let xs:Vec<int> = ss.map(|s|from_str::<int>(s).unwrap()).collect(); 
     println!("{}", xs); 
    } 
} 

Это не работает! Rust ответил (а) с ошибкой:

hello.rs:4:12: 4:25 error: borrowed value does not live long enough 
hello.rs:4  let ss = line.unwrap().as_slice().trim().split(' '); 
         ^~~~~~~~~~~~~ 
hello.rs:3:34: 7:3 note: reference must be valid for the block at 3:33... 
hello.rs:3 for line in io::stdin().lines() { 
hello.rs:4  let ss = line.unwrap().as_slice().trim().split(' '); 
hello.rs:5  let xs:Vec<int> = ss.map(|s|from_str::<int>(s).unwrap()).collect(); 
hello.rs:6  println!("{}", xs); 
hello.rs:7 } 
hello.rs:4:3: 4:54 note: ...but borrowed value is only valid for the statement at 4:2; consider using a `let` binding to increase its lifetime 
hello.rs:4  let ss = line.unwrap().as_slice().trim().split(' '); 
       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
error: aborting due to previous error 

Это меня смущает. Является ли line или ss тем, что не живем достаточно долго? И как я могу использовать привязку let для увеличения их продолжительности жизни? Я думал, что я уже использую let?

Я искал в Интернете решения и читал Lifetime guide, но я до сих пор не могу это понять. Может ли кто-нибудь дать мне подсказку?

ответ

9

В вашей второй версии тип ss - CharSplits<'a, char>. Параметр lifetime в типе говорит нам, что объект содержит ссылку. Чтобы присвоение было действительным, ссылка должна указывать на объект, который существует после этого оператора. Однако unwrap() потребляет line; другими словами, он перемещает данные Ok варианта из объекта Result. Поэтому ссылка не указывает внутри оригинала line, а скорее на временный объект.

В вашей первой версии вы потребляете временное выражение в конце длинного выражения, хотя звонок на номер map. Чтобы исправить вторую версию, вы должны связать результат unwrap(), чтобы сохранить значение жить достаточно долго:

use std::io; 

fn main() { 
    for line in io::stdin().lines() { 
     let line = line.unwrap(); 
     let ss = line.as_slice().trim().split(' '); 
     let xs: Vec<int> = ss.map(|s|from_str::<int>(s).unwrap()).collect(); 
     println!("{}", xs); 
    } 
} 
+0

Чтобы убедиться, что я правильно вас понимаю, 'CharSplits' ссылается на значение внутри' line'. Но на самом деле он ссылается на копию, взятую из 'Ok', которая отбрасывается, как только заканчивается строка' let ss'. Вместо того, чтобы сохранить все ценности до конца блока? –

+0

Да. Временные значения действительны только для оператора, в котором находится выражение, которое производит это значение. –

+0

Разве это не пустая трата памяти, чтобы не указывать внутри «линии»? –

3

Речь идет о вызове unwrap(), он получает объект, содержащий объект, но эта ссылка должна пережить объект-контейнер, который выходит за пределы области видимости в следующей строке (локальная привязка к ней отсутствует).

Если вы хотите получить более чистый код, очень распространенный способ, чтобы написать это:

use std::io; 

fn main() { 
    for line in io::stdin().lines() { 
     let xs:Vec<int> = 
      line 
      .unwrap() 
      .as_slice() 
      .trim() 
      .split(' ') 
      .map(
       |s|from_str::<int>(s).unwrap() 
      ) 
      .collect(); 
     println!("{}", xs); 
    } 
} 

Если нет, то вы можете создать в результате связывания «unwraped» и использовать его.

Надеюсь, это помогло.

+0

Так вы говорите, что 'line' выходит за рамки в' пусть xs' линию, но а не в строке 'let ss', даже если они находятся в одном блоке? –

+1

Это результат 'line.unwrap()', который выходит за рамки. – snf

+0

Спасибо, я думаю, что я начинаю это делать. –