rust - Rust 的生命周期

标签 rust lifetime

偶尔我发现自己想要编写可以通过两种方式之一调用的函数:

// 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,如果它对答案有影响的话)

最佳答案

更新 2015-05-16:原始问题中的代码适用于旧版本的 Rust,但概念保持不变。此答案已更新为使用现代 Rust 语法/库。 (本质上就是把~[]改成Vec~str改成String,最后调整代码示例。)

Is my understanding vaguely accurate?
[...]
What is the difference between a parameter of type &str and a parameter of type &'a str in the example above?

是的,这样的一生基本上可以说是“没有限制”。生命周期是一种将输出值与输入连接起来的方法,即 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 的版本没有区别。如果您需要强制执行全局指针(即特殊的 'static 生命周期),或者如果您想要返回一个引用(例如 -> &str ),只有在返回值具有时才可能返回一个引用(例如 'static )生命周期(这必须是一个或多个输入的生命周期,或 'static )。

What is a lifetime? Where can I learn more about them?

生命周期是指指针指向的数据保证存在多长时间,例如全局变量保证“永远”持续(因此它具有特殊的生命周期 @ )。查看它们的一种简洁方法是:生命周期将数据连接到放置其所有者的堆栈框架;一旦该堆栈框架退出,所有者就会超出范围,并且指向/指向该值/数据结构的任何指针都不再有效,并且生命周期是编译器对此进行推理的一种方式。 (使用栈帧 View ,就好像 static 有一个与当前任务关联的特殊栈帧,而 impl 有一个“全局”栈帧)。

还有一个 lifetimes chapter of the book ,并且 this gist (注意,代码现在已经过时但概念仍然正确)是一个简洁的小演示,展示了如何使用生命周期来避免必须复制/分配(具有强大的安全保证:没有悬空指针的可能性)。

And while I'm at it, what is 'self?

从字面上看没什么特别的,只是某些地方要求类型有生命周期(例如在结构/枚举定义和 'self 中),目前 'static'static 是唯一被接受的名称。 'self 用于全局始终有效的指针,static 用于可以有任何生命周期的东西。这是一个错误,调用该(非 self )生命周期除 ojit_code 以外的任何东西都是错误的。


总而言之,我会像这样编写该函数:

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
}

关于rust - Rust 的生命周期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17490716/

相关文章:

hashmap - 如何为我自己的结构实现 Eq 和 Hash 以将它们用作 HashMap 键?

rust - 如何为 Cargo 中的子依赖项指定功能?

Java 作用域和生命周期(内部类)

generics - 在 Rust 中接受 &Vec<T> 和 &Vec<&T> 的函数

rust - Rust 中的多重借用

iterator - 为什么 .flat_map() 和 .chars() 不适用于 std::io::Lines,但适用于字符串向量?

reference - 有没有办法返回对函数中创建的变量的引用?

rust - 如何对 Rust 数组的 2 个可变切片进行操作?

compiler-errors - 特征方法中的 Rust 生命周期不匹配

c++ - 在 C++ 中更改对象的动态类型