Reference 有没有办法返回对函数中创建的变量的引用?

Reference 有没有办法返回对函数中创建的变量的引用?,reference,rust,lifetime,Reference,Rust,Lifetime,我想写一个程序,将写一个文件在两个步骤。 在程序运行之前,文件可能不存在。文件名是固定的 问题是OpenOptions.new().write()可能会失败。在这种情况下,我想调用一个自定义函数trycreate()。其思想是创建文件,而不是打开文件并返回句柄。由于文件名是固定的,trycreate()没有参数,我无法设置返回值的生存期 我如何解决这个问题 use std::io::Write; use std::fs::OpenOptions; use std::path::Path; fn

我想写一个程序,将写一个文件在两个步骤。 在程序运行之前,文件可能不存在。文件名是固定的

问题是
OpenOptions.new().write()
可能会失败。在这种情况下,我想调用一个自定义函数
trycreate()
。其思想是创建文件,而不是打开文件并返回句柄。由于文件名是固定的,
trycreate()
没有参数,我无法设置返回值的生存期

我如何解决这个问题

use std::io::Write;
use std::fs::OpenOptions;
use std::path::Path;

fn trycreate() -> &OpenOptions {
    let f = OpenOptions::new().write(true).open("foo.txt");
    let mut f = match f {
        Ok(file)  => file,
        Err(_)  => panic!("ERR"),
    };
    f
}

fn main() {
    {
        let f = OpenOptions::new().write(true).open(b"foo.txt");
        let mut f = match f {
            Ok(file)  => file,
            Err(_)  => trycreate("foo.txt"),
        };
        let buf = b"test1\n";
        let _ret = f.write(buf).unwrap();
    }
    println!("50%");
    {
        let f = OpenOptions::new().append(true).open("foo.txt");
        let mut f = match f {
            Ok(file)  => file,
            Err(_)  => panic!("append"),
        };
        let buf = b"test2\n";
        let _ret = f.write(buf).unwrap();
    }
    println!("Ok");
}
有没有办法从没有参数的函数返回引用

否(除了对静态值的引用,但这些在这里没有帮助)

但是,您可能需要查看。如果将
main
中的第一行更改为

let  f = OpenOptions::new().write(true).create(true).open(b"foo.txt");
如果文件尚不存在,将创建该文件,这将解决您原来的问题。

您所问的问题 TL;DR:不,不能返回对函数所拥有的变量的引用。如果您创建了变量,或者将变量的所有权作为函数参数,则此项适用

解决 与其尝试返回引用,不如返回一个拥有的对象
String
代替
&str
Vec
代替
&T
T
代替
&T
,等等

如果通过参数获得变量的所有权,请尝试使用(可变)引用,然后返回具有相同生存期的引用

在极少数情况下,可以使用不安全代码返回所拥有的值和对该值的引用。这有许多微妙的要求,你必须坚持,以确保你不会造成未定义的行为或记忆不安全

另见:

更深层次的回答 ,但我想更深入地评论一下,并谈谈代码中的其他一些错误

让我们从返回引用的较小示例开始,并查看错误:

fn try_create<'a>() -> &'a String {
    &String::new()
}
有没有办法从没有参数的函数返回引用

从技术上说,是的,但对于你想要的,是的

引用指向现有内存块。在没有参数的函数中,唯一可以引用的是全局常量(具有生存期
&'static
)和局部变量。现在我将忽略全局

在C语言或C++语言中,你可以引用一个局部变量并返回它。但是,一旦函数返回,就不能保证所引用的内存继续保持原来的状态。它可能会像您期望的那样保持一段时间,但最终内存将被重新用于其他用途。只要代码查看内存并尝试将用户名解释为用户银行帐户中的剩余金额,就会出现问题

这是Rust的生命周期所阻止的-不允许使用引用的值超过其在当前内存位置的有效时间

另见:

你的实际问题 请参阅以下文档:

这会使用一条有用的错误消息来惊慌。当然,在程序内部惊慌失措并不是非常有用,因此建议将错误传播出去:

fn trycreate() -> io::Result<File> {
    OpenOptions::new().write(true).open("foo.txt")
}
我还将从
main
返回
结果。总之,包括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::{
fs::OpenOptions,
io::{self,Write},
};
fn main()->io::Result{
让mut f=OpenOptions::new()
.create(true)
.写(真)
.append(true)
.open(“foo.txt”)?;
f、 写入所有(b“test1\n”)?;
f、 写入所有(b“test2\n”)?;
好(())
}

引用是指针。一旦函数被执行,它们将从执行堆栈中弹出,资源将被取消分配

对于下面的示例,
x
被放置在块的末尾。在该点之后,引用
&x
将指向一些垃圾数据。基本上,它是一个悬空的指针。Rust编译器不允许这样的事情,因为它不安全

fn run()->&u32{
设x:u32=42;
return&x;
}//x被放在这里
fn main(){
设x=run();
}
这是对的详细说明,简要解释了问题,但没有太具体

Rust不允许返回对函数中创建的变量的引用。有解决办法吗?是的,只需将该变量放在a中,然后返回它。例如:

fn run() -> Box<u32> {
    let x: u32 = 42;
    return Box::new(x);
} 

fn main() {
    println!("{}", run());
}

注意:在C++中,返回对堆栈局部变量的引用是未定义的行为;如果它看起来起作用,你就是不走运。在常见情况下,编译器应该检测到问题并发出警告。@MatthieuM。只是一个警告。。。多么不安全:-)虽然这表明我已经好几年没有为一份日常工作写过C了,因为我从来没有看到过这些警告。很高兴看到所有营地都取得了进展@谢普马斯特:你一定使用了一个旧的编译器;我仍然停留在gcc 4.3.2上,而且我有它!但是,是的,只是一个警告。大多数C/C++编译器都采取保守的方法:错误由标准强制执行,其余的则通过警告来完成(精度或多或少…@MatthieuM)。我们当然有一个更老的编译器,但可能没有那么旧。当然,我可能从未尝试过将局部变量作为引用返回,但我不知道我是否可以声称自己有那么好。:-)@D3181没有名为
Write
的方法。你正在寻找,并且你需要在范围内具备这种特质。查看.return的Rust 1.0/“write a file”(写入文件)一节,在块的末尾这样做并不惯用。第一个答案不必要地冗长,第二个答案不够详细。选择return作为重点。尽管非惯用的
return
我发现这个答案有最清晰的解释。
let f = OpenOptions::new().write(true).open("foo.txt");
let mut f = f.or_else(|_| trycreate()).expect("failed at creating");
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(())
}
fn run() -> Box<u32> {
    let x: u32 = 42;
    return Box::new(x);
} 

fn main() {
    println!("{}", run());
}
fn run() -> u32 {
    let x: u32 = 42;
    return x;
}