如何正确返回临时值的引用?Rust编译错误求解
问题描述
可正常运行的函数
fn get_suffix(str: Option<&str>) -> u32 { str.and_then( |s| s.rsplit('_').next() ) .and_then( |s| s.parse::<u32>().ok() ) .unwrap_or(0) }
触发编译错误的函数
use std::path::Path; fn get_suffix_from_path(path: &Path) -> u32 { path.file_stem() .and_then( |s| s.to_string_lossy().rsplit('_').next() ) .and_then( |s| s.parse::<u32>().ok() ) .unwrap_or(0) }
编译错误信息
328 | stem.to_string_lossy().rsplit('_').next()) | ----------------------^^^^^^^^^^^^^^^^^^^ | | | returns a value referencing data owned by the current function | temporary value created here
疑问:
- 是否因为
to_string_lossy()创建的String会在闭包结束时立即被销毁? - 解决此问题的惯用方法是什么?
已尝试的可行但不够优雅的写法:
stem.to_string_lossy().rsplit('_').next().and_then(|s| Some(s.to_owned()) )
原因分析与解决方法
错误原因
你的判断完全正确:to_string_lossy()返回Cow<'_, str>类型——如果路径包含非UTF-8字符,它会生成一个临时String;即使路径是合法UTF-8,返回的Cow::Borrowed也是借用这个临时值的内部数据。闭包执行完毕后,这个临时值会被立即销毁,但你试图返回的rsplit('_').next()结果是指向该临时值的引用,导致悬垂引用,Rust借用检查器直接报错阻止这种不安全行为。
惯用解决方法
无需提前复制字符串,只需把解析逻辑移到闭包内部,让临时值的生命周期覆盖解析过程即可:
use std::path::Path; fn get_suffix_from_path(path: &Path) -> u32 { path.file_stem() .and_then(|s| { s.to_string_lossy() .rsplit('_') .next() .and_then(|suffix| suffix.parse::<u32>().ok()) }) .unwrap_or(0) }
这种写法的优势:
- 所有操作在同一个闭包内完成,临时值的生命周期足够覆盖解析步骤,不会出现悬垂引用。
- 仅当后缀能成功解析为
u32时,才会完成必要的字符串转换(若需要),避免不必要的内存分配。
另外,也可以用filter_map让代码逻辑更线性:
use std::path::Path; fn get_suffix_from_path(path: &Path) -> u32 { path.file_stem() .filter_map(|s| s.to_string_lossy().rsplit('_').next()) .filter_map(|s| s.parse::<u32>().ok()) .next() .unwrap_or(0) }
这种写法可读性更强,同样能规避生命周期问题,且代码更简洁。
内容的提问来源于Stack Exchange,提问作者Kodra
相关产品推荐
相关产品推荐

