创建Vec时,借入的价值不能长期使用 [英] Borrowed value does not live long enough when creating a Vec

查看:91
本文介绍了创建Vec时,借入的价值不能长期使用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

编者注:在Rust 1.0之前,曾问过这个问题.从那时起,许多功能和类型都发生了变化,某些语言的语义也发生了变化.问题中的代码不再有效,但答案中表达的想法可能是有效的.

Editor's note: This question was asked before Rust 1.0. Since then, many functions and types have changed, as have certain language semantics. The code in the question is no longer valid, but the ideas expressed in the answers may be.

我正在尝试列出目录中的文件,并将文件名复制到我自己的Vec中.我已经尝试了几种解决方案,但始终会遇到无法创建足够长的生存变量的问题.我不明白我的错误.

I'm trying to list the files in a directory and copy the filename to my own Vec. I've tried several solutions, but it always ends up with a problem of not being able to create long enough living variables. I don't understand my mistake.

fn getList(action_dir_path : &str) -> Vec<&str> {
    let v = fs::readdir(&Path::new(action_dir_path))
            .unwrap()
            .iter()
            .map(|&x| x.filestem_str().unwrap())
            .collect();
    return v;
}

为什么编译器会抱怨"x"?我不在乎x,我想在其中包含&str,我认为&str是静态的.

Why does the compiler complain about "x" ? I don't care about x, I want the &str inside it and I thought &str were static.

我尝试过这种方式,但是在编译器抱怨路径"寿命不足时,我得到了相同的结果.

I tried this way, but I got the same result with the compiler complaining about "paths" not living long enough.

fn getList2(action_dir_path : &str) -> Vec<&str> {
    let paths = fs::readdir(&Path::new(action_dir_path)).unwrap();
    let mut v : Vec<&str> = Vec::new();

    for path in paths.iter(){
       let aSlice = path.filestem_str().unwrap();
       v.push(aSlice);
    }

    return v;
}

这是游乐场.

推荐答案

支持Rust 1.0的代码最直观的翻译是:

The most literal translation of your code that supports Rust 1.0 is this:

use std::{fs, path::Path, ffi::OsStr};

fn getList(action_dir_path: &str) -> Vec<&OsStr> {
    let v = fs::read_dir(&Path::new(action_dir_path))
        .unwrap()
        .map(|x| x.unwrap().path().file_stem().unwrap())
        .collect();
    return v;
}

这会产生错误消息:

2015年锈蚀

error[E0597]: borrowed value does not live long enough
 --> src/lib.rs:6:18
  |
6 |         .map(|x| x.unwrap().path().file_stem().unwrap())
  |                  ^^^^^^^^^^^^^^^^^                    - temporary value only lives until here
  |                  |
  |                  temporary value does not live long enough
  |
note: borrowed value must be valid for the anonymous lifetime #1 defined on the function body at 3:1...
 --> src/lib.rs:3:1
  |
3 | / fn getList(action_dir_path: &str) -> Vec<&OsStr> {
4 | |     let v = fs::read_dir(&Path::new(action_dir_path))
5 | |         .unwrap()
6 | |         .map(|x| x.unwrap().path().file_stem().unwrap())
7 | |         .collect();
8 | |     return v;
9 | | }
  | |_^

2018年锈蚀

error[E0515]: cannot return value referencing temporary value
 --> src/lib.rs:6:18
  |
6 |         .map(|x| x.unwrap().path().file_stem().unwrap())
  |                  -----------------^^^^^^^^^^^^^^^^^^^^^
  |                  |
  |                  returns a value referencing data owned by the current function
  |                  temporary value created here

问题来自 Path::file_stem .这是签名:

The problem comes from Path::file_stem. This is the signature:

pub fn file_stem(&self) -> Option<&OsStr>

这表示该方法将返回对OsStr借用引用. PathBuf结构是字符串的所有者.当您离开该方法时,没有任何地方拥有PathBuf,因此它将被删除.这意味着对PathBuf的任何引用将不再有效.这是Rust阻止您引用不再分配的内存的方式,对Rust来说是这样!

This indicates that the method will return a borrowed reference to a OsStr. The PathBuf struct is the owner of the string. When you leave the method, there's nowhere left that owns the PathBuf, so it will be dropped. This means that any references into the PathBuf will no longer be valid. This is Rust preventing you from having references to memory that is no longer allocated, yay for Rust!

最简单的方法是返回Vec<String>. String拥有其中的字符串,因此我们不必担心在离开函数时会被释放:

The easiest thing you can do is return a Vec<String>. String owns the string inside of it, so we don't need to worry about it being freed when we leave the function:

fn get_list(action_dir_path: &str) -> Vec<String> {
    fs::read_dir(action_dir_path)
        .unwrap()
        .map(|x| {
            x.unwrap()
                .path()
                .file_stem()
                .unwrap()
                .to_str()
                .unwrap()
                .to_string()
        })
        .collect()
}

我还免费更新了样式,使其更像Rust:

I also updated the style (at no charge!) to be more Rust-like:

  1. snake_case用于项目
  2. 类型定义中的冒号前没有空格
  3. 没有理由只设置一个变量来返回它.
  4. 除非您要从函数中退出,否则不要使用显式的return语句.
  5. 无需将路径包装在Path中.
  1. Use snake_case for items
  2. No space before the colon in type definitions
  3. There's no reason to set a variable just to return it.
  4. Don't use explicit return statements unless you are exiting from a function early.
  5. There's no need to wrap the path in a Path.

但是,我不喜欢所有展开的内容.我会这样写函数:

However, I'm not a fan of all of the unwrapping. I'd write the function like this:

use std::{ffi::OsString, fs, io, path::Path};

fn get_list(action_dir_path: impl AsRef<Path>) -> io::Result<Vec<OsString>> {
    fs::read_dir(action_dir_path)?
        .map(|entry| entry.map(|e| e.file_name()))
        .collect()
}

fn main() {
    println!("{:?}", get_list("/etc"));
}

除上述更改外:

  1. 我对输入路径使用通用类型.
  2. 我返回Result以便将错误传播给调用方.
  3. 我直接向DirEntry询问文件名.
  4. 我将类型保留为OsString.
  1. I use a generic type for the input path.
  2. I return a Result to propagate errors to the caller.
  3. I directly ask the DirEntry for the filename.
  4. I leave the type as an OsString.

这篇关于创建Vec时,借入的价值不能长期使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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