first liftime
fn main() {
let a = String::from("aaaaa"); // a goes into scope
{
let b = String::from("bbb"); // b goes into scope
let res = longest(&a, &b);
println!("{}", res);
} // b goes out of scope
}// a goes out of scope
fn longest(x: &str, y: &str) -> &str {
if x.len() > y.len() {
x
} else {
y
}
}
比较哪个变量长,这个代码是无法编译通过的
编译错误也很清楚,告诉我们,要声明一个lifetime,因为返回值引用了入参,所以编译器不知道返回值的生命周期是什么
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
什么一个 ‘a 作为lifetime parameter, 这告诉编译器,longest的返回值的声明周期和入参一样,这里 ‘a 并不是代表,x, y的生命周期是一致的,而是说 返回值 str,x, y 只要在 ‘a 这个scope中就可以,例如,例子里面 a 的生命周期要比 b,res都要长,但他们有一个交集,就是b和res的lifetime
假如这里声明2个lifetime
fn longest<'a, 'b>(x: &'a str, y: &'b str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
编译就会报错,但是可以告诉编译器,’a 一定 比 ‘b 活的久
fn longest<'a:'b, 'b>(x: &'a str, y: &'b str) -> &'b str {
if x.len() > y.len() {
x
} else {
y
}
}
其实这里 ‘a, ‘b 并不是和参数x,y 绑定的,只是定义了2个lifetime,告诉编译器,不管x,y 的生命周期如何,返回值的生命周期一定在那个短命的scope里,这里我觉得是
struct
#[derive(Debug)]
struct Config<'a> {
query: &'a String,
filename: String,
case_sensitive: bool,
}
impl <'a> Config<'a> {
fn new(query: &'a String) -> Result<Self, &'static str> {
if query.len() <= 0 {
return Err("invalid argument");
}
Ok(Self{query, filename: String::from("test"), case_sensitive: false})
}
}
假如struct中有个变量是引用,那也需要申明一个生命周期, 这告诉编译器,Config实例的生命周期,和传入query属性的生命周期一致
fn main() {
let q = String::from("query"); // q comes into scope
let cfg = Config::new(&q).unwrap_or_else(|err| { // cfg comes into scope
eprintln!("failed to create config {}", err);
process::exit(1)
});
println!("{:?}", cfg);
println!("{}", cfg.get_query());
} // cfg, q goes out of scope
how to break it?
fn main() {
let q = String::from("query"); // q comes into scope
move_string(q); // q is dead after move_string, so this will not compile
let cfg = Config::new(&q).unwrap_or_else(|err| { // cfg comes into scope
eprintln!("failed to create config {}", err);
process::exit(1)
});
println!("{:?}", cfg);
println!("{}", cfg.get_query());
} // cfg, q goes out of scope
#[derive(Debug)]
struct Config<'a> {
query: &'a String,
filename: String,
case_sensitive: bool,
}
fn move_string(s: String){
}
lifetime Bounds
当struct包含泛型参数的时候,T有可能是另外一个struct,这个struct也可能包含其他的引用,例如
struct Ref<'a, T>(&'a T);
Because
T
can be any type,T
could be a reference or a type that holds one or more references, each of which could have their own lifetimes. Rust can’t be sureT
will live as long as'a
.
struct Ref<'a, T: 'a>(&'a T);
Adding lifetime bounds on
T
to specify that any references inT
live at least as long as'a
elision rule
- The first rule is that each parameter that is a reference gets its own lifetime parameter.
- The second rule is if there is exactly one input lifetime parameter, that lifetime is assigned to all output lifetime parameters:
fn foo<'a>(x: &'a i32) -> &'a i32
. - The third rule is if there are multiple input lifetime parameters, but one of them is
&self
or&mut self
because this is a method, the lifetime ofself
is assigned to all output lifetime parameters. This third rule makes methods much nicer to read and write because fewer symbols are necessary.