Rust中规避`temporary value dropped while borrowed`错误的惯用方法?
temporary value dropped while borrowed错误的惯用方法? 问题背景
我在Rust里用迭代器(尤其是处理&str或String的迭代器),或者读取文件的时候,经常碰到*temporary value dropped while borrowed*这个老问题。举个典型的错误示例:
fn main() { let s = Some("a".to_string()); let s: &str = s.unwrap().as_str(); dbg!(s); }
这段代码会直接报错,因为unwrap()返回的String是一个无主临时值,在as_str()调用后就会被销毁,导致后续的&str变成悬垂引用。
常规解决方法(但略显繁琐)
最直接的修复方式就是专门定义一个变量来持有这个临时值,延长它的生命周期:
fn main() { let s = Some("a".to_string()); let temp: String = s.unwrap(); let s: &str = temp.as_str(); dbg!(s); }
这样temp持有了String的所有权,s的引用生命周期就和temp绑定,编译器就不会报错了。
理想中的简洁写法(目前不存在)
但这种写法真的很打断思路——上面的例子很简单,但在处理复杂迭代器链时,为了存一个临时值,我得硬生生打断整个链式调用流程。我心里一直觉得应该有更简洁的写法,比如这样:
fn main() { let s = Some("a".to_string()); let s: &str = s.unwrap().define!().as_str(); dbg!(s); }
这里用到了一个假想的define!宏,它相当于一个“就地存临时值”的方法宏,能把左侧的String临时存成一个匿名变量,让后续的as_str()能安全借用它。
当前Rust中的可行性探讨
我也想过能不能用现有Rust宏实现类似功能,比如改成这样的调用方式:
let s: &str = define!(s.unwrap()).as_str();
理论上这个宏展开后应该等价于:
let __temp_s = s.unwrap(); let s: &str = __temp_s.as_str();
但问题在于,Rust宏的展开范围无法超出它的调用上下文——它是写在let s: &str = ...这个赋值语句内部的,没法凭空在语句外部生成新的变量定义,所以这种实现存在本质上的语法限制。
说实话我就是不想每次都为了存临时值打断思路,或者回头去补变量定义,这就是日常和编译器较劲的小麻烦。真的很想知道有没有现有Rust里的写法能解决这个,或者是不是我这个需求本身就不太合理?
备注:内容来源于stack exchange,提问作者Illumin

