认识生命周期
声明周期基础
通常来说:
当一个函数返回一个引用时,该应用的来源只有两种情况
- 来自函数参数
- 来自函数内部新创建的变量
- 第一种情况需要我们显式的标注生命周期,
- 第二种情况是永远不被允许的。除非为 'static
fn main() { // 例如比较两个字符串切片的长度,返回长的那个 /* fn longest(x: &str, y: &str) -> &str { if(x.len() > y.len()) { x } else { y } } */ // 因为返回的是一个引用类型 编译器无法知晓其被引用的变量存活状态 // 因此我们要显式的标注返回值与函数参数直接的生命周期关系 fn longest<'a>(x: &'a str, y: &'a str) -> &'a str { if x.len() > y.len() { x } else { y } } // 将x的作用域记作 'a, y也为'a, 表示他们在同一个作用域中,拥有相同的生命周期 // 表示x和y至少活得和'a 一样久,至于到底活多久或者哪个活得更久,抱歉我们都无法得知 // 生命周期标准并没有实际性的作用,仅仅是告诉编译器多个引用之间的关联关系 let x = String::from("hello"); let y: &str = "world!"; let max_char = longest(&x, y); println!("{}", max_char); { let m = "longest"; let n = longest(m, &x); // x在这个作用域中依然有效 println!("{}", n); // m在这里仍然存活. n是m的引用,依然有效 } let n; { let m = String::from("longest"); n = longest(&x, &m); // ERROR: m的生命周期不够长 } // <- m在这里已经被销毁了 // println!("{}", n); // <- 如果这里再访问n, n是m的引用,则报错 // 结构体中的生命周期 #[derive(Debug)] struct Person<'a> { name: &'a str } let cxk = Person { name: "cxk" }; println!("cxk: {:?}", cxk); // 为具有生命周期的结构体实现方法 // 'a: 'b 为生命周期约束写法,表示'b必须比'a小 ('a必须比'a活得久) impl <'a: 'b, 'b> Person<'a> { fn name_len(&self) -> usize { self.name.len() } fn name_longest(&self, target: &'b str) -> &'b str { if self.name_len() > target.len() { self.name } else { target } } } println!("cxk: {:?}", cxk.name_longest("hello")); // 静态生命周期标注 fn get_ip_type(is_ipv6: bool) -> &'static str { if is_ipv6 { "ipv6" } else { "ipv4" } } println!("{}, {}", get_ip_type(false), get_ip_type(true)); }