string - 遍历文件中的行并从 vec 中查找子字符串!生锈
问题描述
我正在编写一个System
可以从数据文件构造结构的项目。在数据文件中,一些行包含关键字,这些关键字指示要在该行内或在随后的 N 行中读取的值(用该行中的空白行分隔)。
我想要一个vec!
包含关键字(在编译时静态已知),检查迭代器返回的行是否包含关键字并执行适当的操作。
现在我的代码如下所示:
impl System {
fn read_data<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>> where P: AsRef<Path> {
let file = File::open(filename)?;
let f = BufReader::new(file);
Ok(f.lines())
}
...
pub fn new_from_data<P>(dataname: P) -> System where P: AsRef<Path> {
let keywd = vec!["atoms", "atom types".into(),
"Atoms".into()];
let mut sys = System::new();
if let Ok(mut lines) = System::read_data(dataname) {
while let Some(line) = lines.next() {
for k in keywd {
let split: Vec<&str> = line.unwrap().split(" ").collect();
if split.contains(k) {
match k {
"atoms" => sys.natoms = split[0].parse().unwrap(),
"atom types" => sys.ntypes = split[0].parse().unwrap(),
"Atoms" => {
lines.next();
// assumes fields are: atom-ID molecule-ID atom-type q x y z
for _ in 1..=sys.natoms {
let atline = lines.next().unwrap().unwrap();
let data: Vec<&str> = atline.split(" ").collect();
let atid: i32 = data[0].parse().unwrap();
let molid: i32 = data[1].parse().unwrap();
let atype: i32 = data[2].parse().unwrap();
let charge: f32 = data[3].parse().unwrap();
let x: f32 = data[4].parse().unwrap();
let y: f32 = data[5].parse().unwrap();
let z: f32 = data[6].parse().unwrap();
let at = Atom::new(atid, molid, atype, charge, x, y, z);
sys.atoms.push(at);
};
},
_ => (),
}
}
}
}
}
sys
}
}
我非常不确定两点:
- 我不知道我是否以惯用的方式逐行读取文件,因为我修补了书中的一些示例和 Rust 示例。但是返回一个迭代器让我想知道何时以及如何解开结果。例如,当在 while 循环中调用迭代器时,我是否必须像 in 一样解包两次
let atline = lines.next().unwrap().unwrap();
?我认为编译器还没有抱怨,因为它遇到的第一个错误是 - 当我得到一个典型的值时,我无法理解赋予值 k 的类型:
error[E0308]: mismatched types
--> src/system/system.rs:65:39
|
65 | if split.contains(k) {
| ^ expected `&str`, found `str`
|
= note: expected reference `&&str`
found reference `&str`
error: aborting due to previous error
我们应该如何声明子字符串并将其与我输入的字符串进行比较keywd
?我试图在包含中尊重 k,告诉它查看 &keywd 等,但我只是觉得我在浪费时间没有正确解决问题。在此先感谢,确实感谢任何帮助。
解决方案
让我们一一解决问题。我将通过它们出现在代码中的内容。
首先,您需要keywd
在for
循环中借用,即&keywd
. 因为否则keywd
会在循环的第一次迭代后移动while
,因此编译器会抱怨这一点。
for k in &keywd {
let split: Vec<&str> = line.unwrap().split(" ").collect();
接下来,当您调用.unwrap()
时line
,这是同样的问题。这会导致内部Ok
值移出Result
. 相反,您可以这样做line.as_ref().unwrap()
,然后您获得对内部Ok
值的引用并且不使用line
结果。
或者,您可以.filter_map(Result::ok)
在您的lines
, 上完全避免 ( .as_ref()
) .unwrap()
。
您可以将其直接添加到read_data
甚至简单地使用返回类型impl ...
。
fn read_data<P>(filename: P) -> io::Result<impl Iterator<Item = String>>
where
P: AsRef<Path>,
{
let file = File::open(filename)?;
let f = BufReader::new(file);
Ok(f.lines().filter_map(Result::ok))
}
请注意,您正在line
为each 拆分keywd
,这是不必要的。所以你也可以把它移到你的for
循环之外。
总而言之,它最终看起来像这样:
if let Ok(mut lines) = read_data("test.txt") {
while let Some(line) = lines.next() {
let split: Vec<&str> = line.split(" ").collect();
for k in &keywd {
if split.contains(k) {
...
既然我们借了&keywd
,那么我们不需要像现在一样更改k
为。&k
k
&&str
推荐阅读
- sql - emp 更改商店时的前 3 名员工
- javascript - JQuery html 方法中的 HTML 代码不起作用(它显示内容但 javascript 调用不起作用)
- r - 如何编写一个for循环来计算R中数据集每列的最大值?
- mysql - 使用mysql选择随机记录
- rest - Peoplesoft 集成代理 REST 服务 POST - 如何在 Peoplesoft 中设置
- c - 如何让 C 中的标准输入从另一个程序中读取外部数据?
- android - android-sdk 工具上的标签不匹配太多,无法构建 docker 映像
- sql - 用于检查特定日期格式的 SQL Case 语句
- azure - 来自特定网站的必应新闻搜索结果
- python - 如何将小时数添加到数据框中的原始时间然后生成新日期?