Copyright © 2022-2025 aizws.net · 网站版本: v1.2.6·内部版本: v1.25.2·
页面加载耗时 0.00 毫秒·物理内存 145.1MB ·虚拟内存 1437.8MB
欢迎来到 AI 中文社区(简称 AI 中文社),这里是学习交流 AI 人工智能技术的中文社区。 为了更好的体验,本站推荐使用 Chrome 浏览器。
lifetime,生命周期。rust把生命周期提到了语法糖的层面,解决引用-借用问题。
lifetime机制,确保解决所有的borrow借用是有效的。
lifetime和scope有关联,但有差别。
例1,最简单的用法:
//'a 表示一个生命周期,'b也类似
//'a 表示,函数print_refs的生命周期不超过'a,同理,'b也类似。
//也就是说,生命周期'a超过函数print_refs,同理, 'b也是
fn print_refs<'a, 'b>(x: &'a i32, y: &'b i32) {
println!("x is {} and y is {}", &x, &y);
}
fn main() {
let x = 1;
let y = 2;
print_refs(&x, &y);
}
所有的引用都必须有一个生命周期。
函数的返回值,要么是有生命周期的引用,要么是静态变量。
如果编译器能推导引用的生命周期,那么代码里可以省略生命周期变量。
例2,省略的生命周期:
//下面两个函数如果同名,则函数签名是完全一样的
// 输入参数是引用,生命周期省略了
fn elided_input(x: &i32) {
println!("`elided_input`: {}", x);
}
// 输入参数是引用,生命周期没有省略,效果跟前一个函数是一样的,函数签名也是一样的
fn annotated_input<'a>(x: &'a i32) {
println!("`annotated_input`: {}", x);
}
// 返回值和入参的生命周期可以省略,如果修改为同名,下面两个函数也有相同的函数签名
//返回值和输入参数没生命周期
fn elided_pass(x: &i32) -> &i32 { x }
//返回值和输入参数有生命周期
fn annotated_pass<'a>(x: &'a i32) -> &'a i32 { x }
fn main() {
let x = 3;
elided_input(&x);
annotated_input(&x);
println!("`elided_pass`: {}", elided_pass(&x));
println!("`annotated_pass`: {}", annotated_pass(&x));
}
例3,入参出参的生命周期,以及返回值的生命周期
//入参的生命周期'a
fn print_one<'a>(x: &'a i32) {
println!("`print_one`: x is {}", x);
}
//可变参数也有生命周期
fn add_one<'a>(x: &'a mut i32) {
*x += 1;
}
//多个入参,各自有不同生命周期,当然也可以设置成相同寿命周期
fn print_multi<'a, 'b>(x: &'a i32, y: &'b i32) {
println!("`print_multi`: x is {}, y is {}", x, y);
}
//返回值是引用,也有生命周期
fn pass_x<'a, 'b>(x: &'a i32, _: &'b i32) -> &'a i32 { x }
//这个函数会报错。String::from("foo")在函数体内被创建,scope是这个函数
//函数运行结束,这个变量就要被析构,内存释放。因此,它的引用不能作为返回值。
/*
fn invalid_output<'a>() -> &'a String { &String::from("foo") }
| ^-------------------
| ||
| |temporary value created here
| returns a reference to data owned by the current function
*/
//fn invalid_output<'a>() -> &'a String { &String::from("foo") }
fn main() {
let x = 7;
let y = 9;
print_one(&x);
print_multi(&x, &y);
let z = pass_x(&x, &y);
print_one(z);
let mut t = 3;
add_one(&mut t);
print_one(&t);
}
关于Bounds:
T: 'a //T里的所有引用,都可以在'a生命周期之外存活
T: Trait+'a //T实现Trait特质,且T内的所有引用,都在'a生命周期之外存活。
例子4:
use std::fmt::Debug;
// Ref是一个tuple,'a是生命周期,'a生命周期比tuple更长
// tuple只有一个元素,这个元素是一个引用,是T的引用,这个引用的生命周期比Ref更长
// T内部的所有引用都在生命周期'a,都超过Ref。
#[derive(Debug)]
struct Ref<'a, T: 'a>(&'a T);
// 一个打印的范型函数。它的入参是范型T,且范型T必须实现Debug特质。
// 因为实现了Debug特质,这个打印函数根据Debug特质进行打印。
// 这个where指示T的属性
fn print<T>(t: T) where T: Debug {
println!("`print`: t is {:?}", t);
}
// 这个print_ref函数,跟上面的print函数不同之处:
// 这里的入参是引用,因此必须有生命周期。
// 生命周期的意思是,T的生命周期是'a,比print_ref生命周期更长,T的所有引用都在'a
// +'a 表示 a生命周期一定在print_ref外头
fn print_ref<'a, T>(t: &'a T) where T: Debug + 'a {
println!("`print_ref`: t is {:?}", t);
}
fn main() {
//x绑定到栈上的对象i32 7
let x = 7;
//ref_x是一个tuple,第一个元素是一个引用,因为有引用,所在定义Ref的时候要有生命周期'a
//有生命周期'a,表示第一个元素的引用在Ref的外头,生命周期比Ref长,'a生命周期比Ref长
//包含Ref生命周期
let ref_x = Ref(&x);
//入参是引用,所以用print_ref函数打印
//入参是引用,因此函数定义必须有生命周期
print_ref(&ref_x);
//常规print,这句可以运行。但如果放到print_ref之前,这句会报错。
print(ref_x);
}
例子5,'static也是一种生命周期
// x的bound是T
// T是'static + Display特质
//T实现了Display特质,这样函数generic里才能println!宏打印x
fn generic<T>(x: T) where T: 'static + std::fmt::Display {
println!("x = {}", x);
}
fn main(){
// A reference with 'static lifetime:
//s是静态生命周期变量
let s: &'static str = "hello world";
generic(s);
}
例子6,生命周期bound
use std::fmt::Debug;
//input的bound:input的生命周期是'static,input也实现Debug特质
fn print_it( input: impl Debug + 'static )
{
println!( "'static value passed in is: {:?}", input );
}
fn use_it()
{
// i是'static
let i = 5;
print_it(i);
// oops, &i only has the lifetime defined by the scope of
// use_it(), so it's not 'static:
// &i的生命周期是use_it函数,所以不是'static,因此这句会报错
print_it(&i);
/*
18 | print_it(&i);
| ---------^^-
| | |
| | borrowed value does not live long enough
| argument requires that `i` is borrowed for `'static`
*/
}
fn main(){
use_it();
}
在 rust 比较两个对象,检查它们是否相等,应该是哪种相等呢? 比如,一段代码: let mut vec = vec![1, 2, 3];vec.push(4);assert_eq!(vec, [1, 2, ...