Подтвердить что ты не робот

Время жизни в ржавчине

Иногда я обнаружил, что хочу писать функции, которые могут быть вызваны одним из двух способов:

// With a string literal:
let lines = read_file_lines("data.txt");

// With a string pointer:
let file_name = ~"data.txt";
let lines = read_file_lines(file_name);

Мое первое предположение заключалось в использовании заимствованного указателя (&str) для типа параметра, но когда это не сработало (это позволило мне использовать @str и ~str), я попробовал следующее ( путем копирования библиотек Rust), которые действительно работали.

fn read_file_lines<'a>(path: &'a str) -> ~[~str] {
    let read_result = file_reader(~Path(path));
    match read_result {
        Ok(file) => file.read_lines(),
        Err(e) => fail!(fmt!("Error reading file: %?", e))
    }
}

Проблема в том, что я не понимаю, что делаю. Из того, что я могу собрать (в основном из ошибок компилятора), я объявляю время жизни, на котором нет ограничений, и используя его для описания параметра пути (что означает, что любое время жизни может быть передано как параметр).

Итак:

  • Насколько я понимаю, я понимаю?
  • Что такое жизнь? Где я могу узнать больше о них?
  • В чем разница между параметром типа &str и параметром типа &'a str в приведенном выше примере?
  • И пока я нахожусь, что это 'self?

(я использую Rust 0.7, если это имеет значение для ответа)

4b9b3361

Ответ 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
}