Rust错误案例:error[E0716]: temporary value dropped while borrowed

发布时间 2023-11-19 19:01:44作者: KLangHu

原因

出现error[E0716]: temporary value dropped while borrowed的情况往往是因为错误地将引用绑定在了临时变量上,在每行代码结尾的分号;处,临时变量释放导致引用的错误绑定。

由于临时变量多出现于函数编程中,因此该问题多发于连续调用函数。

简短案例

// entry: PathBuf
let folder_path = entry.path().parent().ok_or_else(|| anyhow!("No folder path"))?
fs::create_dir(folder_path).expect("Error while creating dir");

以上代码中会出现error[E0716]: temporary value dropped while borrowed

这是因为,在 Rust 中,当你调用一个方法或函数,方法的返回值通常是一个临时值,除非它被绑定到一个变量上。这个临时值只在当前的语句中有效,也就是说,在分号;到达之前,它都是有效的。

一旦当前语句执行完毕,所有的临时值都会被立即丢弃(除非它们被移动或借用到了另一个生命周期更长的地方)。

看这两行代码执行中发生的事:

  1. entry.path() 调用返回了一个临时的 PathBuf 对象。
  2. 然后立即在这个临时的 PathBuf 对象上调用了 parent() 方法,它返回了一个指向 Path 的临时引用,即 Option<&Path>。
  3. 接着在这个 Option<&Path> 上调用 ok_or_else,如果 Option 是 Some,它就会返回里面的值,如果是 None,它会调用闭包来产生一个错误值。

问题就出在第三步。如果 parent() 返回 None,ok_or_else 将会调用闭包来创建一个 Err,这是没问题的,因为 Err 里面的值是立即创建的。但如果 parent() 返回 Some,ok_or_else 试图直接返回一个引用(&Path),这个引用指向的是 entry.path() 的结果,这是一个临时值。

在 ok_or_else 调用结束后,这个临时值(PathBuf 对象)会被丢弃,但你在 let folder_path 中尝试将一个引用赋值给 folder_path 变量,这个引用指向的内容却在它能被使用之前就被销毁了。

所以,当在下一行代码使用 folder_pathfolder_path引用了一个已经不存在的对象,这违反了 Rust 的借用规则:你不能拥有指向已经被销毁数据的引用。这是 Rust 的所有权和生命周期特性的一部分,确保了引用的安全性和数据的有效性。

正确的做法是将entry.path()返回值绑定在一个变量中,即在引用前延长其生命周期:

let tmp_var = entry.path(); // 通过临时变量来延长entry.path()返回的&PathBuf生命周期,确保在上下文中有足够长的生命周期
let folder_path = tmp_var.parent().ok_or_else(|| anyhow!("No folder path"))?
fs::create_dir(folder_path).expect("Error while creating dir");