gpt4 book ai didi

rust - 如何从已拆分成多个部分的文件创建行迭代器?

转载 作者:行者123 更新时间:2023-11-29 08:23:24 25 4
gpt4 key购买 nike

我有一个文件,我需要逐行阅读并分成两个句子,用“=”分隔。我正在尝试使用迭代器,但我找不到如何在 split 中正确使用它。文档说 std::str::Split 实现了这个特征,但我仍然不知道如何使用它。

use std::{
fs::File,
io::{prelude::*, BufReader},
};

fn example(path: &str) {
for line in BufReader::new(File::open(path).expect("Failed at opening file.")).lines() {
let words = line.unwrap().split("="); //need to make this an iterable
}
}

我如何使用一个我知道已经实现到类似 split 的特征?

最佳答案

作为@Mateen commented , split已经返回一个可迭代对象。要解决生命周期问题,请保存 unwrap() 返回的值在调用 split 之前进入一个变量.

我将在这里尝试解释生命周期问题。

首先,查看函数签名确实很有帮助。

pub fn unwrap(self) -> T
pub fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P>

unwrap非常简单,它拥有自己的所有权并返回内在值(value)。

split看起来很吓人,其实也不难,'a只是生命周期的名称,它只是说明返回值可以使用多长时间。在这种情况下,这意味着两个输入参数必须至少与返回值一样长。

//                   Takes by reference, no ownership change
// v
pub fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P>
// ^ ^ ^ ^
// | |--|---| |
// This just declares a name. | |
// | |
// Both of these values must last longer than -----|

这是因为split不复制任何字符串,它只是指向原始字符串上发生拆分的位置。如果原始字符串由于某种原因被丢弃,Split不会指向无效数据。

一个变量的生命周期(除非所有权被传递给其他东西)一直持续到它超出范围,这要么在结束时}如果它被命名(例如使用 let )或者它在行尾/;

这就是为什么您的代码中存在生命周期问题:

for line in std::io::BufReader::new(std::fs::File::open(path).expect("Failed at opening file.")).lines() {
let words = line
.unwrap() // <--- Unwrap consumes `line`, `line` can not be used after calling unwrap(),
.split("=") // Passed unwrap()'s output to split as a reference
; //<-- end of line, unwrap()'s output is dropped due to it not being saved to a variable, the result of split now points to nothing, so the compiler complains.
}

解决方案

保存unwrap()的返回值

for line in std::io::BufReader::new(std::fs::File::open("abc").expect("Failed at opening file.")).lines() {
let words = line.unwrap();
let words_split = words.split("=");
} // <--- `word`'s lifetime ends here, but there is no lifetime issues since `words_split` also ends here.

您可以重命名 words_splitwords如果您愿意,可以隐藏原始变量以免弄乱变量名称,这也不会引起问题,因为隐藏变量不会立即删除,而是在其原始范围的末尾删除。

或者

而不是使用类型为 str 的迭代器,所有这些都只是指向原始字符串的奇特指针,您可以将每个切片复制到它自己的字符串中,从而消除对将原始字符串保留在范围内的依赖。

在您的情况下,几乎可以肯定没有理由这样做,因为复制每个切片需要更多的处理能力和更多的内存,但 Rust 为您提供了这种控制权。

let words = line
.unwrap()
.split("=")
.map(|piece|
piece.to_owned() // <--- This copies all the characters in the str into it's own String.
).collect::<Vec<String>>()
; // <--- unwrap()'s output dropped here, but it doesn't matter since the pieces no longer points to the original line string.

let words_iterator = words.iter();

collect给你错误 cannot infer type因为你没有说明你想收集什么,要么使用上面的 turbofish 语法,要么在 words 上声明它即 let words: Vec<String> = ...

您必须调用 collect因为map除非您使用它,否则不会做任何事情,但这超出了本答案的范围。

关于rust - 如何从已拆分成多个部分的文件创建行迭代器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53938867/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com