为何两段Rust代码作用域表现不同?值未越界问题解析
为什么Rust中调用函数时有的值不会触发作用域问题?
先看你提到的两段示例代码:
报错的第一段代码
struct Owned { data: i32, } struct Borrowed<'a> { ref_data: &'a i32, } fn create_something() -> Borrowed<'_> { let o = Owned { data: 42 }; Borrowed { ref_data: &o.data } // 报错:`o` does not live long enough } fn main() { let _b = create_something(); }
正常运行的第二段代码
struct Owned { data: i32, } struct Borrowed<'a> { ref_data: &'a i32, } fn create_something(other_bla: &Owned) -> Borrowed<'_> { Borrowed { ref_data: &other_bla.data } } fn main() { let o = Owned { data: 42 }; let b = create_something(&o); println!("{}", b.ref_data); // 正常输出42 }
核心差异:引用指向的原始数据生命周期,而非参数本身的生命周期
第一段里,
create_something函数内的o是函数本地的Owned实例,它的生命周期只到函数执行完毕为止。函数结束后,o会被栈自动销毁,此时返回的Borrowed结构体里的引用就指向了一块已经被释放的内存——这就是Rust绝对不允许的“悬垂引用”,所以借用检查器直接报错拦截。第二段里,函数参数
other_bla确实是栈上的一个引用副本,函数结束后这个副本会被弹出栈,但关键是:这个引用副本指向的原始数据是main函数里创建的o,o的生命周期覆盖了整个main函数的执行过程,包括create_something调用结束后b存在的时间段。返回的Borrowed结构体里的引用,本质上是直接指向main中的o.data,而不是栈上的other_bla参数。参数本身只是个指针副本,它的销毁完全不影响原始数据的存在。
说白了,Rust的借用检查器根本不关心作为参数的引用副本活多久,它只关心引用所指向的原始数据能不能活到引用被使用的时刻。只要原始数据的生命周期足够长,即使参数的副本被销毁,引用依然是安全有效的。
内容的提问来源于stack exchange,提问作者mandiromi
相关产品推荐
相关产品推荐

