Rust生活

Dan*_*iel 47 lifetime rust

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

// 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);
Run Code Online (Sandbox Code Playgroud)

我的第一个猜测是使用借用的指针(&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))
    }
}
Run Code Online (Sandbox Code Playgroud)

问题是我不明白我在做什么.从我可以收集的内容(主要来自编译器错误),我宣布一个没有限制的生命周期,并使用它来描述path参数(意味着任何生命周期都可以作为参数传递).

所以:

  • 我的理解是否模糊准确?
  • 什么是一生?我在哪里可以了解更多相关信息?
  • 在上面的例子中&str,类型参数和类型参数之间有什么区别&'a str
  • 虽然我在这,但是什么'self

(我正在使用Rust 0.7,如果它对答案有所影响)

huo*_*uon 56

更新2015-05-16:原始问题中的代码应用于旧版本的Rust,但概念保持不变.此答案已更新为使用现代Rust语法/库.(本质上改变~[]Vec~strString和调节在最末尾代码的例子.)

我的理解是否模糊准确?
[...]
类型&str的参数和上面示例中&'str类型的参数之间有什么区别?

是的,这样的一生就基本上说"没有限制".生命周期是一种将输出值与输入连接起来的方式,即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,这完全等同于编写未使用的变量生命周期.ie fn(path: &str) -> Vec<String>'as 版本没什么区别.离开生命周期的唯一时间不同于包括它是否需要强制执行全局指针(即特殊'static生命周期),或者如果要返回引用(例如-> &str),只有在返回值具有生命周期时才可以(这必须是一个或多个输入的生命周期,或者'static).

什么是一生?我在哪里可以了解更多相关信息?

生命周期是指针指向的数据保证存在多长时间,例如全局变量保证持续"永久"(因此它具有特殊的生命周期'static).查看它们的一种巧妙方法是:生命周期将数据连接到其所有者所在的堆栈框架; 一旦该堆栈帧退出,所有者就会超出范围,并且指向/进入该值/数据结构的任何指针都不再有效,并且生命周期是编译器解释此问题的一种方式.(使用堆栈帧视图,就好像@有一个与当前任务关联的特殊堆栈帧,并且statics具有"全局"堆栈帧).

本书还有一个生命周期章节,这个要点(注意代码现已过时,但概念仍然是真的)是一个简洁的小演示,说明如何使用生命周期来避免复制/分配(具有强大的安全性)保证:没有悬挂指针的可能性).

虽然我在这,但是什么'self

字面上没什么特别的,只是某些地方需要类型才能有生命周期(例如在结构/枚举定义和impls中),并且目前'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
}
Run Code Online (Sandbox Code Playgroud)

  • 谢谢!看起来你在我的例子中指定生命周期是正确的.我想我需要0.6才能使用`'static str`s',但升级到0.7后没有重新测试. (2认同)