外观
雷区 3:E0597 借条过期了(悬垂引用)
报错码:E0597
症状
rust
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() {
x
} else {
y
}
}
fn main() {
let result;
{
let short = String::from("短");
result = longest("很长很长", &short);
}
println!("{}", result);
}编译输出
text
error[E0597]: `short` does not live long enough
--> src/main.rs:13:34
|
12 | let short = String::from("短");
| ----- binding `short` declared here
13 | result = longest("很长很长", &short);
| ^^^^^^ borrowed value does not live long enough
14 | }
| - `short` dropped here while still borrowed
15 | println!("{}", result);
| ------ borrow later used here诊断
"借出去的东西,自己先没了。"
longest 的返回值要么借自 x,要么借自 y(都行,看谁长)。short 在大括号里出生,大括号一关就没了;可 result 拿着它的借条,大括号外面还要用——借条比东西活得久。
这就是悬垂引用(dangling reference):借的东西已经被清理了,借条还攥在手里。C 语言里这是噩梦般的 bug(可能崩、可能读到垃圾数据);Rust 在编译时就拦下了它——看报错最后一句:"short dropped here while still borrowed"(东西没了,借条还在)。
解药
解药一:让短命的东西活到借条用完——把 short 提到外面:
rust
fn main() {
let short = String::from("短");
let result;
{
result = longest("很长很长", &short);
}
println!("{}", result);
}解药二:不借,改成"拥有"——返回 String 而不是 &str,谁要谁拿走(真实项目最常用):
rust
fn longest_owned(x: &str, y: &str) -> String {
if x.len() > y.len() {
x.to_string()
} else {
y.to_string()
}
}
fn main() {
let result = longest_owned("很长很长", "短");
println!("{}", result);
}解药二为什么常用?
"借"意味着"东西的寿命由别人决定"。函数要返回一个自己造出来的东西(或不确定谁活得久的东西),直接返回拥有所有权的值(String)最省心——不用纠结寿命。代价是可能多一次复制,但正确性永远优先。
预防
- E0597 的时间线:
binding declared here(出生)→borrowed value does not live long enough(借了)→dropped here while still borrowed(没了)→borrow later used here(还要用)。"借的比活的久",就是悬垂 - 函数返回引用前,先问:返回的引用借自参数吗?借自参数,寿命由参数定,安全;借自函数内部自己造的东西,永远不能返回引用(那是 E0515,和 E0597 一家人)
- 图省心,返回拥有所有权的值:第 9 章的
longest_text能返回&str是因为两个参数都活着;真实项目里,String返回值往往更省心