面试题答案
一键面试设计要点
- 明确生命周期参数:在涉及结构体间引用关系时,为结构体和方法显式声明生命周期参数,确保编译器能清晰知晓引用的生命周期范围。例如,如果一个结构体持有对另一个结构体的引用,要在结构体定义中体现这个引用的生命周期。
- 确保引用生命周期足够长:被引用的数据的生命周期必须长于或等于引用它的数据的生命周期。比如,若一个局部变量作为引用被传递到一个结构体实例中,这个局部变量的生命周期不能短于该结构体实例,否则会出现悬空引用。
- 避免循环引用:循环引用会导致难以确定生命周期,可能使编译器无法正确分析引用关系,从而引发编译错误。尽量设计数据结构以避免结构体间相互持有强引用形成循环。
示例代码
// 定义观察者 trait
trait Observer {
fn update(&mut self, data: i32);
}
// 定义被观察对象
struct Subject {
data: i32,
observers: Vec<Box<dyn Observer>>,
}
impl Subject {
fn new() -> Self {
Subject {
data: 0,
observers: Vec::new(),
}
}
fn attach(&mut self, observer: Box<dyn Observer>) {
self.observers.push(observer);
}
fn set_data(&mut self, new_data: i32) {
self.data = new_data;
self.notify();
}
fn notify(&mut self) {
for observer in &mut self.observers {
observer.update(self.data);
}
}
}
// 实现一个具体的观察者
struct ConcreteObserver {
name: String,
}
impl Observer for ConcreteObserver {
fn update(&mut self, data: i32) {
println!("{} observed new data: {}", self.name, data);
}
}
你可以这样使用:
fn main() {
let mut subject = Subject::new();
let mut observer1 = ConcreteObserver {
name: "Observer1".to_string(),
};
let mut observer2 = ConcreteObserver {
name: "Observer2".to_string(),
};
subject.attach(Box::new(observer1));
subject.attach(Box::new(observer2));
subject.set_data(42);
}
在上述代码中,Subject
结构体持有 Observer
特征对象的 Vec
,避免了循环引用问题。在 attach
方法中添加观察者时,生命周期通过 Box
来管理,确保了引用关系的正确性,避免了生命周期相关的编译错误。