有什么方法可以返回对在函数中创建的变量的引用? [英] Is there any way to return a reference to a variable created in a function?

查看:231
本文介绍了有什么方法可以返回对在函数中创建的变量的引用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I want to write a program that will write a file in 2 steps. It is likely that the file may not exist before the program is run. The filename is fixed.

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

The problem is that OpenOptions.new().write() can fail. In that case, I want to call a custom function trycreate(). The idea is to create the file instead of opening it and return a handle. Since the filename is fixed, trycreate() has no arguments and I cannot set a lifetime of the returned value.

如何解决此问题?

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

推荐答案

fjh绝对正确,但我想进行更深入的注释,并在代码中触及其他一些错误.

fjh is absolutely correct, but I want to comment a bit more deeply and touch on some of the other errors with your code.

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

Let's start with a smaller example of returning a reference and look at the errors:

fn try_create<'a>() -> &'a String {
    &String::new()
}

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 {
  |               ^^

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?

从技术上说是",但是对于您想要的是否".

Technically "yes", but for what you want, "no".

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

A reference points to an existing piece of memory. In a function with no arguments, the only things that could be referenced are global constants (which have the lifetime &'static) and local variables. I'll ignore globals for now.

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

In a language like C or C++, you could actually take a reference to a local variable and return it. However, as soon as the function returns, there's no guarantee that the memory that you are referencing continues to be what you thought it was. It might stay what you expect for a while, but eventually the memory will get reused for something else. As soon as your code looks at the memory and tries to interpret a username as the amount of money left in the user's bank account, problems will arise!

这就是Rust的生命周期所防止的-不允许使用超出引用值在其当前内存位置有效的时间之外的引用.

This is what Rust's lifetimes prevent - you aren't allowed to use a reference beyond how long the referred-to value is valid at its current memory location.

返回一个拥有的对象,而不是尝试返回引用. String代替&strVec<T>代替&[T]T代替&T,等等.

Instead of trying to return a reference, return an owned object. String instead of &str, Vec<T> instead of &[T], T instead of &T, etc.

另请参阅:

  • 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 的文档

Look at the documentation for OpenOptions::open:

fn open<P: AsRef<Path>>(&self, path: P) -> Result<File>

它返回一个Result<File>,所以我不知道您期望如何返回一个OpenOptions或对它的引用.如果将其改写为:

It returns a Result<File>, so I don't know how you'd expect to return an OpenOptions or a reference to one. Your function would work if you rewrote it as:

fn trycreate() -> File {
    OpenOptions::new()
        .write(true)
        .open("foo.txt")
        .expect("Couldn't open")
}

这使用 Result::expect 出现有用的错误消息时出现恐慌.当然,惊慌于程序的胆汁并不是超级有用,因此建议您将错误传播出去:

This uses Result::expect to panic with a useful error message. Of course, panicking in the guts of your program isn't super useful, so it's recommended to propagate your errors back out:

fn trycreate() -> io::Result<File> {
    OpenOptions::new().write(true).open("foo.txt")
}

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

Option and Result have lots of nice methods to deal with chained error logic. Here, you can use 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的建议:

I'd also return the Result from main. All together, including fjh's suggestions:

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(())
}

这篇关于有什么方法可以返回对在函数中创建的变量的引用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆