【问题标题】:Unable to return a vector of string slices: borrowed value does not live long enough无法返回字符串切片向量:借来的值不够长
【发布时间】:2016-08-10 08:32:40
【问题描述】:

我是 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 经验水平,我无法想象这些变量的生命周期。任何帮助都将不胜感激,因为我已经花了一两个小时试图解决这个问题。

【问题讨论】:

  • 您是否看过其他任何“x 寿命不够长”的 stackoverflow 问题?您正在lex 函数中创建一个新的String,然后尝试将引用返回到该String,即使String 的寿命不超过lex 函数,因此您的引用将指向空白。
  • 我是否必须在函数外部定义字符串并传入一个可变引用,或者有没有办法延长函数内部定义的字符串的生命周期,以便它可以比lex 函数寿命更长?
  • 你永远无法延长生命。我有一个解决您的问题的方法,但如果您不想将其标记为重复,则需要更改您的问题。它应该说明为什么它与询问如何返回对拥有对象的引用的所有其他问题不同。
  • 副本将是stackoverflow.com/q/29428227/155423;但你可以花点时间让它变得与众不同。

标签: vector rust borrowing


【解决方案1】:

问题是您在lex 函数内分配了一个新的String (token_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&lt;'a&gt;(input: &amp;String, buffer: &amp;'a mut String) -&gt; Vec&lt;&amp;'a str&gt; 此签名将指定返回的&amp;strs 的生命周期至少与传入的缓冲区的生命周期一样长。

如果您可以容忍额外的分配,另一种方法是只返回 Vec&lt;String&gt; 而不是 Vec&lt;&amp;str&gt;

【讨论】:

  • 感谢您的帮助。现在这很有意义。
猜你喜欢
  • 2016-10-25
  • 2016-06-10
  • 2017-03-11
  • 2020-07-23
  • 1970-01-01
  • 1970-01-01
  • 2016-01-06
  • 1970-01-01
  • 2014-12-26
相关资源
最近更新 更多