你提出的问题
TL;DR:不,你不能返回一个由函数拥有的变量的引用。无论是你创建的变量还是作为函数参数取得所有权。
解决方案
不要试图返回引用,而是返回一个拥有所有权的对象。例如,返回 String
而不是 &str
,返回 Vec<T>
而不是 &[T]
,返回 T
而不是 &T
,等等。
如果你通过参数获取了变量的所有权,请尝试获取一个(可变)引用,然后返回相同生命周期的引用。
在极少数情况下,你可以使用不安全的代码来返回拥有值和对其的引用。这有许多微妙的要求,你必须遵守这些要求,以确保你不会导致未定义的行为或内存不安全。
另请参见:
更深入的答案
fjh 是完全正确的,但我想更深入地评论一下你的代码中的其他错误。
让我们从返回引用的较小示例开始,并查看错误:
fn try_create<'a>() -> &'a String {
&String::new()
}
Rust 2015
error[E0597]: borrowed value does not live long enough
--> src/lib.rs:2:6
|
2 | &String::new()
| ^^^^^^^^^^^^^ temporary value does not live long enough
3 | }
| - temporary value only lives until here
|
note: borrowed value must be valid for the lifetime 'a as defined on the function body at 1:15...
--> src/lib.rs:1:15
|
1 | fn try_create<'a>() -> &'a String {
| ^^
Rust 2018
error[E0515]: cannot return reference to temporary value
--> src/lib.rs:2:5
|
2 | &String::new()
| ^-------------
| ||
| |temporary value created here
| returns a reference to data owned by the current function
有没有办法在没有参数的函数中返回引用?从技术上讲,“是的”,但对于您想要的内容,“不行”。引用指向现有的内存片段。在没有参数的函数中,唯一可以引用的是全局常量(具有生命周期`&'static`)和本地变量。我们先忽略全局变量。在像C或C++这样的语言中,您实际上可以引用本地变量并返回它。但是,一旦函数返回,就不能保证您所引用的内存仍然是您认为的那样。它可能会保持您期望的一段时间,但最终该内存将被重新用于其他用途。一旦您的代码查看内存并尝试将用户名解释为用户银行账户中剩余的金额,问题就会出现!这就是Rust生命周期的作用-您不允许超出所引用值在其当前内存位置有效的时间长度。另请参见:
Is it possible to return either a borrowed or owned type in Rust?和
Why can I return a reference to a local literal but not a variable?您实际的问题
请查看OpenOptions::open
的文档:
fn open<P: AsRef<Path>>(&self, path: P) -> Result<File>
该函数返回一个Result<File>
,因此我不知道您会如何返回OpenOptions
或其引用。如果您将其重写为以下方式,则该函数将起作用:
fn trycreate() -> File {
OpenOptions::new()
.write(true)
.open("foo.txt")
.expect("Couldn't open")
}
使用Result::expect
来生成一个有用的错误信息并引发panic。当然,在程序的核心部分引发panic并不是非常有用的,因此建议将错误传播回去:
fn trycreate() -> io::Result<File> {
OpenOptions::new().write(true).open("foo.txt")
}
Option
和Result
有很多处理链式错误逻辑的好方法。在这里,你可以使用or_else
:
let f = OpenOptions::new().write(true).open("foo.txt");
let mut f = f.or_else(|_| trycreate()).expect("failed at creating");
我也会返回
main
中的
Result
。所有这些,包括fjh的建议:
use std::{
fs::OpenOptions,
io::{self, Write},
};
fn main() -> io::Result<()> {
let mut f = OpenOptions::new()
.create(true)
.write(true)
.append(true)
.open("foo.txt")?;
f.write_all(b"test1\n")?;
f.write_all(b"test2\n")?;
Ok(())
}
std::borrow::Cow
来泛化拥有的数据和未拥有的引用--它是一个Deref
,让您选择给定实例是否拥有或借用其数据。我发现这是在返回拥有和未拥有的数据之间切换的最可靠方法。 - BallpointBen