如何为接收并返回引用的闭包声明生命周期约束?
问题:闭包生命周期导致Rust代码无法编译
我尝试编写get_longest_time_window函数,通过reduce闭包遍历self.data,闭包接收两个Element引用并返回其中一个。理论上该代码应合法,但因闭包涉及的三个引用的生命周期关系未明确而无法编译,我猜测所有生命周期应相同,但不知如何用Rust语法表达,请问该代码是否可行?如何修改使其编译?
原始代码:
use std::collections::BTreeSet; struct Element { pub data: String, // arbitrary pub time_window: u64, } struct Machine { data: BTreeSet<Element> } impl Machine { fn new() -> Machine { let machine = Machine { data: BTreeSet::new() }; return machine; } fn get_longest_time_window(&self) -> Option<u64> { let lambda = |lhs: &Element, rhs: &Element| -> &Element { return if lhs.time_window >= rhs.time_window { lhs } else { rhs } }; let selected = self.data.iter().reduce(lambda); return selected.map(|x| {x.time_window}); } } fn main() { let machine = Machine::new(); let max_time_window = machine.get_longest_time_window(); println!("max_time_window = {:?}", max_time_window); }
解答
这段代码是可行的,问题出在编译器无法自动推断闭包中输入和输出引用的生命周期一致性。以下是两种解决方案:
方案1:显式标注闭包的生命周期
通过'_生命周期占位符,告诉编译器闭包的输入和输出引用共享相同的生命周期(即迭代器元素的生命周期),让编译器确认引用关系合法:
use std::collections::BTreeSet; struct Element { pub data: String, // arbitrary pub time_window: u64, } struct Machine { data: BTreeSet<Element> } impl Machine { fn new() -> Machine { Machine { data: BTreeSet::new() } } fn get_longest_time_window(&self) -> Option<u64> { // 显式标注所有引用的生命周期一致 let lambda = |lhs: &'_ Element, rhs: &'_ Element| -> &'_ Element { if lhs.time_window >= rhs.time_window { lhs } else { rhs } }; self.data.iter().reduce(lambda).map(|x| x.time_window) } } fn main() { let machine = Machine::new(); let max_time_window = machine.get_longest_time_window(); println!("max_time_window = {:?}", max_time_window); }
方案2:使用更简洁的max_by_key方法
既然你的需求是找到time_window最大的元素,直接使用标准库迭代器提供的max_by_key方法是更符合Rust习惯的写法,它会自动处理生命周期,代码也更简洁:
use std::collections::BTreeSet; struct Element { pub data: String, // arbitrary pub time_window: u64, } struct Machine { data: BTreeSet<Element> } impl Machine { fn new() -> Machine { Machine { data: BTreeSet::new() } } fn get_longest_time_window(&self) -> Option<u64> { // 直接根据time_window字段查找最大值 self.data.iter() .max_by_key(|elem| elem.time_window) .map(|x| x.time_window) } } fn main() { let machine = Machine::new(); let max_time_window = machine.get_longest_time_window(); println!("max_time_window = {:?}", max_time_window); }
两种方案都能正常编译运行,方案2的语义更清晰,推荐使用。
内容的提问来源于stack exchange,提问作者user2138149
相关产品推荐
相关产品推荐

