[英]Iterating over lines in a file and looking for substring from a vec! in rust
我正在編寫一個項目,其中可以從數據文件構建結構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
}
}
我對兩點非常不確定:
let atline = lines.next().unwrap().unwrap();
那樣解包兩次? ? 我認為編譯器還沒有抱怨,因為它遇到的第一個錯誤是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
我們應該如何聲明 substring 並將其與我放入keywd
的字符串進行比較? 我試圖在 contains 中引用 k,告訴它查看 &keywd 等,但我只是覺得我在浪費時間,因為我沒有正確解決問題。 提前致謝,非常感謝您的幫助。
讓我們 go 一一道來。 我將 go 通過它們出現在代碼中。
首先需要在for
循環中借用keywd
,即&keywd
。 因為否則keywd
在while
循環的第一次迭代之后被移動,因此編譯器為什么會抱怨這個。
for k in &keywd {
let split: Vec<&str> = line.unwrap().split(" ").collect();
接下來,當您line
調用.unwrap()
時,這是同樣的問題。 這導致內部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))
}
請注意,您正在為每個keywd
拆分line
,這是不必要的。 所以你也可以把它移到你的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
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.