Ответ 1
Обновление 2015-05-16: код в исходном вопросе применяется к старой версии Rust, но концепции остаются неизменными. Этот ответ был обновлен, чтобы использовать современный синтаксис/библиотеки Rust. (По существу изменяя ~[]
до Vec
и ~str
до String
и корректируя пример кода в конце.)
Насколько я понимаю, я понимаю? [...]
В чем разница между параметром типа & str и параметром типа & 'a str в примере выше?
Да, такая жизнь в целом говорит "без ограничений", вроде. Lifetimes - способ подключения выходных значений со входами, т.е. fn foo<'a, T>(t: &'a T) -> &'a T
говорит, что foo
возвращает указатель с тем же временем жизни, что и t
, то есть данные, на которые он указывает, действительны в течение того же периода времени, что и t
(ну, строго, по крайней мере до тех пор, пока). Это в основном означает, что возвращаемое значение указывает на некоторый подраздел памяти, на который указывает t
.
Итак, функция типа fn<'a>(path: &'a str) -> Vec<String>
очень похожа на запись { let x = 1; return 2; }
... это неиспользуемая переменная.
Rust назначает времена жизни по умолчанию при записи &str
, и это в точности эквивалентно записи времени жизни неиспользуемой переменной. то есть fn(path: &str) -> Vec<String>
не отличается от версии с 'a
s. Единственное время, оставшееся от жизни, отличается от того, в том числе, если вам нужно обеспечить глобальный указатель (т.е. Специальное время жизни 'static
), или если вы хотите вернуть ссылку (например, -> &str
), которая возможна только в том случае, если возвращаемое значение имеет время жизни (и это должно быть либо время жизни одного или нескольких входов, либо 'static
).
Что такое жизнь? Где я могу узнать больше о них?
Время жизни - это то, как долго гарантируется существование указателя, на которое указывает указатель. глобальная переменная - это гарантия навсегда "навсегда" (поэтому она получила специальное время жизни 'static
). Один из опрятных способов взглянуть на них: жизнь соединяет данные со стеком, на котором размещен их владелец; как только этот стек стека завершается, владелец выходит из области видимости, и любые указатели на/в это значение/структуру данных больше недействительны, а время жизни - это способ, по которому компилятор может рассуждать об этом. (С представлением фрейма стека, как будто @
имеет специальный стек стека, связанный с текущей задачей, и static
имеет "глобальный" стек стека).
Там также глава жизни жизни и этот смысл (NB, теперь код устаревшие, но концепции по-прежнему верны) представляет собой аккуратную небольшую демонстрацию того, как можно использовать время жизни, чтобы избежать необходимости копировать/распределять (с надежной гарантией безопасности: нет возможности оборванных указателей).
И пока я нахожусь, что это
'self
?
Буквально ничего особенного, только определенные места требуют, чтобы типы имели времена жизни (например, в struct/enum defintions и в impl
s), а в настоящее время 'self
и 'static
являются единственными принятыми именами. 'static
для глобальных всегда действующих указателей, 'self
для того, что может иметь любое время жизни. Это ошибка, называющая это (не static
) время жизни чем-либо, кроме self
, ошибкой.
В общем, я бы написал такую функцию, как:
use std::fs::File;
use std::io::prelude::*;
use std::io::BufReader;
use std::path::Path;
fn read_file_lines(path: &Path) -> Vec<String> {
match File::open(path) {
Ok(file) => {
let read = BufReader::new(file);
read.lines().map(|x| x.unwrap()).collect()
}
Err(e) => panic!("Error reading file: {}", e)
}
}
fn main() {
let lines = read_file_lines(Path::new("foo/bar.txt"));
// do things with lines
}