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

标签 reference rust lifetime

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

问题是 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");
}

最佳答案

你问的问题

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

解决方案

与其尝试返回一个引用,不如返回一个拥有的对象。 String而不是 &str , Vec<T>而不是 &[T] , T而不是 &T

如果您通过参数获取变量的所有权,请尝试获取(可变)引用,然后返回相同生命周期的引用。

在极少数情况下,您可以使用不安全代码返回拥有的值对其的引用。这有许多您必须坚持的微妙要求,以确保您不会导致未定义的行为或内存不安全。

另见:

更深层次的回答

fjh is absolutely correct , 但我想更深入地评论一下,并谈谈您的代码中的其他一些错误。

让我们从一个返回引用的小例子开始,看看错误:

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

Is there any way to return a reference from a function without arguments?

技术上"is",但对于您想要的,“否”。

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

在像 C 或 C++ 这样的语言中,您实际上可以获取对局部变量的引用并将其返回。但是,一旦函数返回,无法保证您引用的内存仍然是您认为的那样。它可能会在一段时间内保持您的预期,但最终内存将被重新用于其他用途。一旦您的代码查看内存并尝试将用户名解释为用户银行帐户中剩余的金额,问题就会出现!

这就是 Rust 的生命周期所阻止的——你不能使用超过引用值在其当前内存位置的有效时间的引用。

另见:

你的实际问题

查看 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")
}

OptionResult有很多不错的方法来处理链式错误逻辑。在这里,您可以使用 or_else :

let f = OpenOptions::new().write(true).open("foo.txt");
let mut f = f.or_else(|_| trycreate()).expect("failed at creating");

我还会返回 Result来自 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(())
}

关于reference - 有没有办法返回对函数中创建的变量的引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32682876/

相关文章:

enums - 返回具有 'static tell the compiler this value doesn' t 的类型是否具有关联的生命周期,或者它是否使该值静态?

java - 为什么它的值会改变?

rust - 如何对使用 crate 中特征的函数进行文档测试?

rust - 如何使用 winit rust crate 中的 raw_window_handle() 方法?

rust - 使用 `and_then`如何返回Result <(),String>

reference - 有什么方法可以返回对在函数中创建的变量的引用?

vue.js - 视觉 : Access Vue component method inside rendered named slot

c++ - 函数按引用传递

php - 引用php代码部分

rust - 如何注释此 Rust/Calloop 回调代码的生命周期?