rust 关于使用flatmap函数的借位检查器的问题

v6ylcynt  于 2023-10-20  发布在  其他
关注(0)|答案(2)|浏览(120)

我是新的生 rust 和来掌握如何所有权和借用检查工程
我写了一个小函数

pub fn count_words(file_path: &str) -> Result<usize, Error> {
    return File::open(file_path).map(|file| {
        let reader = BufReader::new(file);
        return reader
            .lines()
            .map(|line| line.unwrap())
            .flat_map(|line| line.split_whitespace())
            .count();
    });
}

我得到这个错误

error[E0515]: cannot return value referencing function parameter `line`
  --> src/lib.rs:19:30
   |
19 |             .flat_map(|line| line.split_whitespace())
   |                              ----^^^^^^^^^^^^^^^^^^^
   |                              |
   |                              returns a value referencing data owned by the current function
   |                              `line` is borrowed here
   |
   = help: use `.collect()` to allocate the iterator

我不确定我是否理解了这里发生的事情(因为哪个实体正在借用行,所以我不能调用分割空白)。
我设法让这个版本运行

pub fn count_words(file_path: &str) -> Result<usize, io::Error> {
    return File::open(file_path).map(|file| {
        let reader = BufReader::new(file);
        let lines = reader.lines();
        let mut num_words = 0;
        for line in lines {
            num_words += line.unwrap().split_whitespace().count();
        }
        return num_words
    });
}
jaql4c8m

jaql4c8m1#

Rust在这里遇到了麻烦,因为它创建了对line的短期引用,而这些引用必须在变量定义的范围之外持久化。
既然你真的不关心行的内容,那么直接使用count就可以了:

BufReader::new(file)
    .lines()
    .map(|line| line.unwrap())
    .map(|line| line.split_whitespace().count())
    .sum()

在这里你可以很容易地把所有这些分裂的计数加起来。这大概就是您在更详细版本中所做的,但我认为这种代码在其Rust-ness方面读起来更好。
这里很明显,您可以通过将两个map()操作合并为一个来进一步减少代码量。

yk9xbfzb

yk9xbfzb2#

这个问题是由于.split_whitespace()返回一个迭代器,它将在每次迭代时referline,但是line,它是一个拥有的String,一旦闭包返回,就会被删除。
line仍然存在的情况下,需要消耗这个迭代器的每次迭代。这里是另一个公式,仍然具有函数式风格(而不是显式循环)。
请注意,我在.map_while()中用.unwrap()交换了.ok(),以避免在无法检索行时出现panic!()。(虽然没有任何评论,但我猜这是对我之前尝试中未触发的Clippy lint的暗示。

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

pub fn count_words(file_path: &str) -> Result<usize, Error> {
    Ok(BufReader::new(File::open(file_path)?)
        .lines()
        .map_while(|line| {
            line.ok().map(|line| line.split_whitespace().count())
        })
        .sum())
}

fn main() {
    println!("{:?}", count_words("src/main.rs"))
}
/*
Ok(33)
*/

相关问题