面试题答案
一键面试trait Trait {
fn do_something(&self);
}
struct Struct1;
struct Struct2;
impl Trait for Struct1 {
fn do_something(&self) {
println!("Struct1 is doing something");
}
}
impl Trait for Struct2 {
fn do_something(&self) {
println!("Struct2 is doing something");
}
}
fn main() {
let mut vec: Vec<Box<dyn Trait>> = Vec::new();
vec.push(Box::new(Struct1));
vec.push(Box::new(Struct2));
// 遍历并调用方法,使用不可变引用
for item in &vec {
item.do_something();
}
}
生命周期分析
- 避免悬垂引用:
- 在 Rust 中,
Box<dyn Trait>
这样的类型已经负责管理其内部对象的生命周期。当我们将Box<dyn Trait>
放入Vec
中时,Vec
会负责管理这些Box
的生命周期。 - 当我们遍历
Vec
时,使用for item in &vec
,这里item
是一个对Box<dyn Trait>
的不可变引用。由于item
的生命周期只在for
循环内部,并且vec
在整个for
循环期间是有效的,所以不会产生悬垂引用。因为vec
持有Box
,而Box
持有具体的结构体实例,只要vec
存在,其内部的Box
和结构体实例就存在。
- 在 Rust 中,
- 确保引用的有效性:
- 在 Rust 中,编译器会根据借用规则来确保引用的有效性。在上述代码中,
for item in &vec
创建的是不可变引用。不可变引用遵循 Rust 的借用规则,即同一时间可以有多个不可变引用,但不能有可变引用。 - 因为
vec
在遍历期间没有被修改(如果尝试在遍历vec
的同时修改vec
,编译器会报错),所以这些不可变引用是有效的。并且vec
的生命周期足够长,能够覆盖for
循环中item
的生命周期,从而保证了item
引用的有效性。
- 在 Rust 中,编译器会根据借用规则来确保引用的有效性。在上述代码中,
如果需要在遍历过程中修改 Vec
中的元素,可以使用可变引用:
trait Trait {
fn do_something(&mut self);
}
struct Struct1;
struct Struct2;
impl Trait for Struct1 {
fn do_something(&mut self) {
println!("Struct1 is doing something");
}
}
impl Trait for Struct2 {
fn do_something(&mut self) {
println!("Struct2 is doing something");
}
}
fn main() {
let mut vec: Vec<Box<dyn Trait>> = Vec::new();
vec.push(Box::new(Struct1));
vec.push(Box::new(Struct2));
// 遍历并调用方法,使用可变引用
for item in &mut vec {
item.do_something();
}
}
在这种情况下,同样要注意 vec
的生命周期要足够长以覆盖 for
循环中可变引用 item
的生命周期,并且同一时间不能有其他对 vec
或其元素的引用,以遵循 Rust 的借用规则确保引用的有效性。