Rust中返回引用的方法与trait实现的疑难问题
Stack Overflow上《rust returning a reference to a integer from a function》问题被标记为重复,参考问题《Why can I return a reference to a local literal but not a variable》指出&42是静态生命周期,但以下代码编译报错:
use std::ops::Deref; struct Curse<T>(T); impl<T> Deref for Curse<T> { type Target = usize; fn deref(&self) -> &<Self as Deref>::Target { &42 // wat } } fn main() { let a = 123; let c = *{ let b = Curse(a); b.deref() }; println!("{a} {c}"); }
报错信息:
Exited with status 101 Standard Error Compiling playground v0.0.1 (/playground) error[E0597]: `b` does not live long enough --> src/main.rs:18:9 | 17 | let b = Curse(a); | - binding `b` declared here 18 | b.deref() | ^ borrowed value does not live long enough 19 | }; | - `b` dropped here while still borrowed For more information about this error, try `rustc --explain E0597`. error: could not compile `playground` (bin "playground") due to 1 previous error Standard Output
修改deref方法的返回签名为&'static <Self as Deref>::Target后,代码可正常编译运行:
use std::ops::Deref; struct Curse<T>(T); impl<T> Deref for Curse<T> { type Target = usize; fn deref(&self) -> &'static <Self as Deref>::Target { &42 // wat } } fn main() { let a = 123; let c = *{ let b = Curse(a); b.deref() }; println!("{a} {c}"); }
疑问点
- 字面量42的生命周期是绑定到
&self的生命周期(存储在栈上),还是本身为静态? - 签名不匹配的trait实现为何被允许?
问题1解答
字面量42本身是**'static生命周期**的,它会被编译到程序的只读数据段中,并非存储在栈上。但第一个错误代码里,Deref trait的deref方法默认签名隐含了生命周期绑定:fn deref(&'a self) -> &'a Target,编译器会自动推导,认为返回的引用生命周期和&self绑定。虽然实际返回的&42是'static,但编译器被签名限制,只能将其生命周期缩短为&self的生命周期,导致后续代码中b被销毁后,引用还被使用,触发E0597错误。
问题2解答
这是因为Rust支持生命周期协变,相关规则允许trait方法实现使用更宽松的生命周期约束:当trait方法的默认签名要求返回的引用生命周期与&self绑定(即'a)时,实现中可以返回更长的生命周期(比如'static)。这种“签名不匹配”其实是合法的——'static生命周期比任意'a都长,完全满足trait签名的约束(返回的引用至少能存活'a那么久),不会导致悬垂引用问题,因此编译器允许这种实现。
内容的提问来源于stack exchange,提问作者FreD

