面试题答案
一键面试- 问题分析:
- 在
process_data
函数中,result.push(&s)
将局部变量s
的引用存入result
中。当for s in input
循环结束,s
会被销毁,但result
中的引用仍然指向已销毁的内存,这就导致了悬垂引用问题。这违反了 Rust 的生命周期规则,即所有引用必须有效且不超过其指向数据的生命周期。
- 在
- 修复思路:
- 我们需要确保
result
中的引用指向的字符串在Bar
实例的生命周期内一直有效。一种方法是延长输入字符串的生命周期,使其与Bar
实例的生命周期一致。可以通过克隆字符串来实现,这样Bar
内部存储的就是字符串的副本而不是引用。
- 我们需要确保
- 修复后的代码:
struct Bar {
data: Vec<String>
}
fn process_data(input: Vec<String>, filters: &[&str]) -> Bar {
let mut result = Vec::new();
for s in input {
for filter in filters {
if s.contains(*filter) {
result.push(s.clone());
break;
}
}
}
Bar { data: result }
}
- 涉及的生命周期规则:
- 借用规则:在 Rust 中,一个值在同一时间只能有一个可变引用,或者多个不可变引用。这里原本的问题是违反了引用生命周期的规则,即引用不能超过其指向数据的生命周期。
- 生命周期标注:在原始代码中,
Bar<'a>
和process_data<'a>
的生命周期标注虽然看似正确,但实际应用中由于s
的局部性导致了悬垂引用。通过修改代码,不再需要显式的生命周期标注,因为 Rust 可以自动推断出正确的生命周期关系。Bar
结构体现在存储String
类型,其生命周期由Bar
实例控制,从而避免了悬垂引用问题。