为何可返回局部字面量引用却不能返回变量?Rust代码编译疑问
为什么能返回局部字面量的引用,却不能返回局部变量的引用?还有那段Rust代码为啥能编译?
这俩问题其实都绕不开Rust的生命周期和值的存储/复制规则,咱们掰开揉碎说:
一、局部字面量vs局部变量的引用返回差异
首先得搞清楚字面量和局部变量的存储位置:
- 像
"hello"、123这类字面量,是被直接编译进程序的二进制文件里的,程序运行时会加载到静态存储区,生命周期是'static——也就是从程序启动到结束一直存在。所以返回它们的引用完全没问题,因为引用指向的东西永远不会被销毁。比如:fn static_str() -> &'static str { "我是静态字面量" } fn static_num_ref() -> &'static i32 { &456 } // 同样可以,整数字面量也是'static - 而局部变量是在函数的栈帧里创建的,函数执行完毕后栈帧会被销毁,局部变量占用的内存也会被释放。如果返回局部变量的引用,这个引用就会变成“悬空引用”——指向已经不存在的内存,这正是Rust要严格禁止的行为,所以编译器会直接报错:
fn local_var_ref() -> &str { let s = String::from("我是局部变量"); &s // 编译错误:返回值的生命周期不足,s会在函数结束后销毁 }
二、那段迭代器代码能编译的原因
咱们再仔细看这段代码:
fn get_iter() -> impl Iterator<Item = i32> { [1, 2, 3].iter().map(|&i| i) } fn main() { let _it = get_iter(); }
关键就在map(|&i| i)这一步:
[1,2,3].iter()返回的是std::slice::Iter<'_, i32>,这个迭代器的Item是&i32——也就是对数组元素的引用,而数组本身是函数内的局部临时值。- 但
map闭包|&i| i做了什么?它把传入的&i32通过模式匹配解引用,直接拿到了i32的值。因为i32是Copy类型,这里会直接复制一份值出来。 - 最终返回的
Map迭代器,它持有的是这些复制出来的i32值,而不是原数组的引用!原数组虽然在函数结束后会被销毁,但迭代器里已经没有任何指向它的引用了,自然不存在生命周期问题。
如果把map去掉,直接返回[1,2,3].iter(),就会编译报错:
// 编译错误:迭代器持有局部数组的引用,生命周期无法满足返回要求 fn get_iter_err() -> impl Iterator<Item = &i32> { [1, 2, 3].iter() }
说白了,就是map把“引用迭代器”转换成了“值迭代器”,完美避开了局部变量引用的生命周期陷阱。
内容的提问来源于stack exchange,提问作者Boiethios
相关产品推荐
相关产品推荐

