[rust初见] 一个关于生命周期的问题
2023-03-18
4 min read
这个问题来自 practice.rs
一个问题
两行注释是编译器给出的报错
/* 使下面代码正常运行 */
struct Interface<'a> {
manager: &'a mut Manager<'a>
}
impl<'a> Interface<'a> {
pub fn noop(self) {
println!("interface consumed");
}
}
struct Manager<'a> {
text: &'a str
}
struct List<'a> {
manager: Manager<'a>,
}
impl<'a> List<'a> {
pub fn get_interface(&'a mut self) -> Interface {
Interface {
manager: &mut self.manager
}
}
}
fn main() {
let mut list = List {
manager: Manager {
text: "hello"
}
};
list.get_interface().noop(); // mutable borrow occurs here
println!("Interface should be dropped here and the borrow released");
use_list(&list); // cannot borrow `list` as immutable because it is also borrowed as mutable
}
fn use_list(list: &List) {
println!("{}", list.manager.text);
}
为什么可变引用的生命周期会持续到最后一行?
- 对于对象的引用 的生命周期是 小于等于 构成该对象的引用类型的字段 的生命周期的.
self本身的生命周期只需要大于等于get_interface内部 +Interface.manager两者中更长的那一个生命周期.- 但是
get_interface函数中self的生命周期被标注为与List::manager::text相同的生命周期. - 再加上后续
main中还有对list的引用, 所以self的生命周期相当于被不合适地标注得更长了, 导致与后续的引用冲突.- 这么说合适吗? 毕竟标注不会延长引用的生命周期
- 但是生命周期注明的 "规则" 会被编译器应用, 用于在无法推断生命周期之间的关系时去使用, 最终检查对象的生命周期是否与使用的实际情况符合.
如何改正?
- 首先需要收敛
self的生命周期, 给它一个和底层text &'a str不同的生命周期. - 又由于
List中的Manager<'a>不是引用, 所以List::manager生命周期和List对象相同. 所以给self与text不同的生命周期会导致List::manager的生命周期与List::manager::text的不同. - 但是
Interface的定义中,Interface::manager与Interface::manager::text被标注成相同的生命周期, 所以需要进一步改变这两者的生命周期关系, 将其分离.
最终的效果
struct Interface<'a, 'b> {
manager: &'a mut Manager<'b>
}
impl Interface<'_, '_> {
pub fn noop(self) {
println!("interface consumed");
}
}
struct Manager<'a> {
text: &'a str
}
struct List<'a> {
manager: Manager<'a>,
}
impl<'a> List<'a> {
pub fn get_interface<'b>(&'b mut self) -> Interface<'b,'a> {
Interface {
manager: &mut self.manager
}
}
}
fn main() {
let text = "hello";
let mut list = List {
manager: Manager {
text
}
};
list.get_interface().noop();
println!("Interface should be dropped here and the borrow released");
use_list(&list);
}
fn use_list(list: &List) {
println!("{}", list.manager.text);
}
总结
- 对于结构体本身的引用 与 其底层引用类型的字段 两者的生命周期是不同的, 前者肯定小于等于后者, 而且一般使用的时候是小于的.
- 结构体中有引用字段的嵌套, 或者多个同级的引用字段, 需要考虑他们之间的生命周期关系.
- 对于上面的代码,
Interface<'a, 'b>中'a'b的关系没有注明, 但其实是有隐式的'b : 'a存在的. - 如果颠倒过来, 就会导致没修改前相同的错误, 本质上还是让 self 的生命周期变大了.
- 对于上面的代码,