首页 文章

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

提问于
浏览
2

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

我理解与Return local String as a slice (&str)的相似之处,但在这种情况下,它只是一个字符串被返回,并不足以让我用我的代码推理我试图返回一个向量 . 根据我的理解,我试图返回对函数块末尾超出范围的 str 类型的引用,所以我应该将 &str 的向量映射到 String 的向量中吗?我不太关心将 &str 转换为 String 的性能影响 . 首先,我想让它发挥作用 .

这是代码,错误在 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);
    }
}

这是错误消息

error: borrowed value does not live long enough
        self.0.borrow().values.get(idx)
        ^~~~~~~~~~~~~~~
reference must be valid for the anonymous lifetime #1 defined on the block at 23:54...
    pub fn value(&self, idx: usize) -> Option<&Value> {
                                                      ^
note: ...but borrowed value is only valid for the block at 23:54
    pub fn value(&self, idx: usize) -> Option<&Value> {
                                                      ^

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

1 回答

  • 2

    问题是你在 lex 函数中分配了一个新的 Stringtoken_string ),然后返回一个对它的引用数组,但是当它最终超出范围时, 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!
    

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

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

相关问题