English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
O mecanismo de ciclo de vida do Rust é um mecanismo de gerenciamento de recursos tão importante quanto o mecanismo de propriedade.
A introdução deste conceito é principalmente para lidar com problemas de gerenciamento de recursos em sistemas de tipos complexos.
A citação é um mecanismo essencial para lidar com tipos complexos, afinal, os dados de tipos complexos não podem ser facilmente copiados e calculados pelos processadores.
Mas a citação frequentemente leva a problemas extremamente complexos de gerenciamento de recursos, primeiramente, vamos nos familiarizar com a referência pendente:
{ let r; { let x = 5; r = &x; } println!("r: {}", r); }
这段代码是不会通过 Rust 编译器的,原因是 r 所引用的值已经在使用之前被释放。
上图中的绿色范围 'a 表示 r 的生命周期,蓝色范围 'b 表示 x 的生命周期。很显然,'b 比 'a 小得多,引用必须在值的生命周期以内才有效。
一直以来我们都在结构体中使用 String 而不用 &str,我们用一个案例解释原因:
fn longer(s1: &'str, s2: &'str) -> &str { if s2.len() > s1.len() { s2 } else { s1 } }
longer 函数取 s1 和 s2 两个字符串切片中较长的一个返回其引用值。但只这段代码不会通过编译,原因是返回值引用可能会返回过期的引用:
fn main() { let r; { let s1 = "rust"; let s2 = "ecmascript"; r = longer(s1, s2); } println!("{} é mais longo", r); }
这段程序中虽然经过了比较,但 r 被使用的时候源值 s1 和 s2 都已经失效了。当然我们可以把 r 的使用移到 s1 和 s2 的生命周期范围内防止这种错误的发生,但对于函数来说,它并不能知道自己以外的地方是什么情况,它为了保障自己传递出去的值是正常的,必选所有权原则消除一切危险,所以 longer 函数并不能通过编译。
生命周期注释是描述引用生命周期的办法。
虽然这样并不能够改变引用的生命周期,但可以在合适的地方声明两个引用的生命周期一致。
生命收起注释用单引号开头,跟着一个小写字母单词:
&i32 // 常规引用 &'a i32 // 含有生命周期注释的引用 &'a mut i32 // 可变型含有生命周期注释的引用
让我们用生命周期注释改造 longer 函数:
fn longer<'a>(s1: &'a str, s2: &'a str) -> &'a str { if s2.len() > s1.len() { s2 } else { s1 } }
我们需要用泛型声明来规范生命周期的名称,随后函数返回值的生命周期将与两个参数的生命周期一致,所以在调用时可以这样写:
fn main() { let r; { let s1 = "rust"; let s2 = "ecmascript"; r = longer(s1, s2); println!("{} é mais longo", r); } }
以上两段程序结合的运行结果:
ecmascript é mais longo
注意:别忘记了自动类型判断的原则。
这是之前留下的疑问,在此解答:
fn main() { struct Str<'a> {} content: &'a str } let s = Str { content: "string_slice" }; println!("s.content = {}", s.content); }
Resultado da Execução:
s.content = string_slice
Se houver definições de métodos para a estrutura Str:
impl<'a> Str<'a> { fn get_content(&self) -> &str { self.content } }
Aqui, o valor de retorno não tem anotação de ciclo de vida, mas não faz mal adicioná-la. É um problema histórico, pois no início o Rust não suportava a automação da decisão de ciclo de vida, todas as vidas precisavam ser declaradas rigorosamente, mas o Rust estável e principal já suporta essa função.
Anotações de ciclo de vida têm uma especial: 'static. Todos os tipos de dados exatos representados por strings constantes entre aspas duplas são &'static str, e o ciclo de vida de 'static é do início ao fim da execução do programa.
use std::fmt::Display; fn longest_with_an_announcement<'a, T>(x: &'a str, y: &'a str, ann: T) -> &'a str where T: Display { println!("Anúncio! {}", ann); if x.len() > y.len() { x } else { y } }
Este programa é extraído do Evangelho do Rust, é um programa que usa ao mesmo tempo generics, traits e o mecanismo de ciclo de vida, não é obrigatório, pode ser experimentado, afinal, cedo ou tarde será necessário!