rust - 借用的值活得不够长(BufReader lines() 到 String 的迭代器)

标签 rust borrow-checker

使用此示例代码:

use std::fs::{File};
use std::io::{BufRead, BufReader};
use std::path::Path;

type BoxIter<T> = Box<Iterator<Item=T>>;

fn tokens_from_str<'a>(text: &'a str) 
-> Box<Iterator<Item=String> + 'a> {
    Box::new(text.lines().flat_map(|s|
        s.split_whitespace().map(|s| s.to_string())
    ))
}

// Returns an iterator of an iterator. The use case is a very large file where
// each line is very long. The outer iterator goes over the file's lines.
// The inner iterator returns the words of each line.
pub fn tokens_from_path<P>(path_arg: P) 
-> BoxIter<BoxIter<String>>
where P: AsRef<Path> {
    let reader = reader_from_path(path_arg);
    let iter = reader.lines()
        .filter_map(|result| result.ok())
        .map(|s| tokens_from_str(&s));
    Box::new(iter)
}

fn reader_from_path<P>(path_arg: P) -> BufReader<File>
where P: AsRef<Path> {
    let path = path_arg.as_ref();
    let file = File::open(path).unwrap();
    BufReader::new(file)
}

我收到此编译器错误消息:

rustc 1.18.0 (03fc9d622 2017-06-06)
error: `s` does not live long enough
  --> <anon>:23:35
   |
23 |         .map(|s| tokens_from_str(&s));
   |                                   ^- borrowed value only lives until here
   |                                   |
   |                                   does not live long enough
   |
   = note: borrowed value must be valid for the static lifetime...

我的问题是:

  • 如何解决这个问题(如果可能,不改变函数签名?)

  • 关于更好的函数参数和返回值有什么建议吗?

最佳答案

一个问题是 .split_whitespace() 获取引用,但不拥有其内容。因此,当您尝试使用拥有对象构建 SplitWhitespace 对象时(调用 .map(|s| tokens_from_str(&s)) 时),字符串 s 被丢弃,而 SplitWhitespace 仍在尝试引用它。我通过创建一个结构来快速修复此问题,该结构获取 String 的所有权并根据需要生成 SplitWhitespace

use std::fs::File;
use std::io::{BufRead, BufReader};
use std::path::Path;
use std::iter::IntoIterator;
use std::str::SplitWhitespace;

pub struct SplitWhitespaceOwned(String);

impl<'a> IntoIterator for &'a SplitWhitespaceOwned {
    type Item = &'a str;
    type IntoIter = SplitWhitespace<'a>;
    fn into_iter(self) -> Self::IntoIter {
        self.0.split_whitespace()
    }
}

// Returns an iterator of an iterator. The use case is a very large file where
// each line is very long. The outer iterator goes over the file's lines.
// The inner iterator returns the words of each line.
pub fn tokens_from_path<P>(path_arg: P) -> Box<Iterator<Item = SplitWhitespaceOwned>>
    where P: AsRef<Path>
{
    let reader = reader_from_path(path_arg);
    let iter = reader
        .lines()
        .filter_map(|result| result.ok())
        .map(|s| SplitWhitespaceOwned(s));
    Box::new(iter)
}

fn reader_from_path<P>(path_arg: P) -> BufReader<File>
    where P: AsRef<Path>
{
    let path = path_arg.as_ref();
    let file = File::open(path).unwrap();
    BufReader::new(file)
}

fn main() {
    let t = tokens_from_path("test.txt");

    for line in t {
        for word in &line {
            println!("{}", word);
        }
    }
}

关于rust - 借用的值活得不够长(BufReader lines() 到 String 的迭代器),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44510445/

相关文章:

rust - use 和 extern crate 有什么区别?

rust - 使用no_std进行的 cargo 测试失败,错误代码为176、160

loops - 具有生命周期界限的递归函数内循环中的借用检查器错误

rust - 为什么不能在同一结构中存储值和对该值的引用?

Rust:在不可变地借用整个 HashMap 的同时修改 HashMap 中的值

rust - 将向量转换为数组并返回

types - 为什么 Rust 不能推断 Iterator::sum 的结果类型?

rust - 在 Diesel 中关联三个表(多对多关系)的标准模式是什么?

rust - 内部可变性与数据隐藏以固定可变借用的所指对象

rust - 如何处理防 rust 借用检查器