MST

星途 面试题库

面试题:Rust函数生命周期参数传递:复杂场景下的应用

假设有如下代码结构: ```rust struct Bar<'a> { data: Vec<&'a str> } fn process_data<'a>(input: Vec<String>, filters: &'a [&str]) -> Bar<'a> { let mut result = Vec::new(); for s in input { for filter in filters { if s.contains(*filter) { result.push(&s); break; } } } Bar { data: result } } ``` 这段代码有什么问题?如何通过正确处理生命周期参数来修复它?请详细说明修复思路和涉及的生命周期规则。
40.3万 热度难度
编程语言Rust

知识考点

AI 面试

面试题答案

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