无法返回字符串切片向量:借用的值存在的时间不够长

Ale*_*x G 5 vector rust borrowing

我是 Rust 的新手,我在使用借用检查器时遇到了一些麻烦。我不明白为什么这段代码不能编译。抱歉,如果这与之前回答的问题很接近,但我似乎无法在我看过的其他问题中找到解决方案。

我理解将本地字符串作为切片(&str)返回的相似性,但在这种情况下,它只是返回一个字符串,不足以让我对我试图返回向量的代码进行推理。据我所知,我试图返回对str将在功能块末尾超出范围的类型的引用,所以我应该将该向量映射&str为向量String吗?我不太关心转换&strString. 首先,我只想让它工作。

这是代码,错误在lex函数中。

use std::io::prelude::*;
use std::fs::File;
use std::env;

fn open(mut s: &mut String, filename: &String) {
    let mut f = match File::open(&filename) {
        Err(_) => panic!("Couldn't open file"),
        Ok(file) => file,
    };
    match f.read_to_string(&mut s) {
        Err(_) => panic!("Couldn't read file"),
        Ok(_) => println!("File read successfully"),
    };

}

fn lex(s: &String) -> Vec<&str> {
    let token_string: String = s.replace("(", " ( ")
        .replace(")", " ) ");

    let token_list: Vec<&str> = token_string.split_whitespace()
        .collect();
    token_list
}

fn main() {
    let args: Vec<_> = env::args().collect();
    if args.len() < 2 {
        panic!("Please provide a filename");
    } else {
        let ref filename = args[1];

        let mut s = String::new();
        open(&mut s, filename);
        let token_list: Vec<&str> = lex(&s);
        println!("{:?}", token_list);
    }
}
Run Code Online (Sandbox Code Playgroud)

这是错误信息

use std::io::prelude::*;
use std::fs::File;
use std::env;

fn open(mut s: &mut String, filename: &String) {
    let mut f = match File::open(&filename) {
        Err(_) => panic!("Couldn't open file"),
        Ok(file) => file,
    };
    match f.read_to_string(&mut s) {
        Err(_) => panic!("Couldn't read file"),
        Ok(_) => println!("File read successfully"),
    };

}

fn lex(s: &String) -> Vec<&str> {
    let token_string: String = s.replace("(", " ( ")
        .replace(")", " ) ");

    let token_list: Vec<&str> = token_string.split_whitespace()
        .collect();
    token_list
}

fn main() {
    let args: Vec<_> = env::args().collect();
    if args.len() < 2 {
        panic!("Please provide a filename");
    } else {
        let ref filename = args[1];

        let mut s = String::new();
        open(&mut s, filename);
        let token_list: Vec<&str> = lex(&s);
        println!("{:?}", token_list);
    }
}
Run Code Online (Sandbox Code Playgroud)

我发现很难解释这段代码,因为以我对 Rust 的经验水平,我无法想象这些变量的生命周期。任何帮助将不胜感激,因为我花了一两个小时试图解决这个问题。

all*_*ons 5

问题是你在函数内部分配了一个 new String( token_string)lex然后返回一个对它的引用数组,但是token_string一旦它在函数结束时超出范围,就会被丢弃(并释放内存)。

fn lex(s: &String) -> Vec<&str> {
    let token_string: String = s.replace("(", " ( ") // <-- new String allocated 
        .replace(")", " ) "); 

    let token_list: Vec<&str> = token_string.split_whitespace()
        .collect();
    token_list // <-- this is just an array of wide pointers into token_string
} // <-- token_string gets freed here, so the returned pointers
  //     would be pointing to memory that's already been dropped!
Run Code Online (Sandbox Code Playgroud)

有几种方法可以解决这个问题。一种方法是强制调用者lex传入您要用于收集的缓冲区。这会将签名更改为此fn lex<'a>(input: &String, buffer: &'a mut String) -> Vec<&'a str>签名将指定返回的&strs 的生命周期至少与传入的缓冲区的生命周期一样长。

另一种方法是只返回 aVec<String>而不是Vec<&str>如果您可以容忍额外的分配。