2017-01-17 39 views
3

這是一個可以生成事物向量的函數,但是由於它涉及到另一個向量,因此存在一些醜陋的解開包裝。從vec pop中移除展開

fn load_into_vec(file_buf: String) -> Vec<Data> { 

    let mut data_vec: Vec<Data> = Vec::new(); 

    for line_iter in file_buf.lines() { 

     let mut line_vec: Vec<&str> = line_iter.split(' ').collect(); 

     let (t1, t2, t3, t4): (u32, u32, u32, u32) = 
     (
      /** ANOTHER WAY TO WRITE THIS? **/ 
      line_vec.pop().unwrap().trim().parse::<u32>().ok().unwrap(), 
      line_vec.pop().unwrap().trim().parse::<u32>().ok().unwrap(), 
      line_vec.pop().unwrap().trim().parse::<u32>().ok().unwrap(), 
      line_vec.pop().unwrap().trim().parse::<u32>().ok().unwrap() 
     ); 

     let mut data_node = Data::new(); 
     data_node.load((t4, t3, t2, t1)); 
     data_vec.push(data_node); 
    } 

    data_vec 
} 

是否有另一種方式來重寫上面塊,而無需使用unwrap或使用unwrap的方式,如果遇到None也不會恐慌?

+0

如果讓它看起來更漂亮是你所有的(而且恐慌)..也許[這樣的東西就足夠了嗎?](http://play.integer32.com/?gist=462d0e57bedae7a31381cee670ba6688&version=stable ) –

+0

有沒有辦法在內部調用unwrap_or_else? – GoldenChrysanthem

+4

我投票結束這個問題作爲題外話,因爲有關改進**已經工作**更好的代碼的問題屬於[Code Review.SE](http://meta.codereview.stackexchange.com/questions/5777 /一個引導到代碼審查換堆棧上溢用戶)。 – Shepmaster

回答

2

您可以使用迭代器和match來編寫更加慣用的循環體。而不是收集到中間Vec,你匹配四次調用iter.next(),以提取你的四個整數。如果其中一個iter.next()調用不成功,您可能會恐慌。

let mut iter = line_iter.split(' ') 
     .map(str::trim) 
     .map(str::parse::<u32>) 
     .map(|s| s.expect("could not parse as u32")) 
     .fuse(); 

    let tup = match (iter.next(), iter.next(), iter.next(), iter.next()) { 
     (Some(t1), Some(t2), Some(t3), Some(t4)) => (t1, t2, t3, t4), 
     _ => panic!("line did not contain at least four numbers"), 
    }; 

    let mut data_node = Data::new(); 
    data_node.load(tup); 

我甚至會去儘可能重寫整個功能:

file_buf.lines() 
    .map(|line_iter| { 
     let mut iter = line_iter.split(' ') 
      .map(str::trim) 
      .map(str::parse::<u32>) 
      .map(|s| s.expect("could not parse as u32")) 
      .fuse(); 

     let tup = match (iter.next(), iter.next(), iter.next(), iter.next()) { 
      (Some(t1), Some(t2), Some(t3), Some(t4)) => (t1, t2, t3, t4), 
      _ => panic!("line did not contain at least four numbers"), 
     }; 

     let mut data_node = Data::new(); 
     data_node.load(tup); 
     data_node 
    }) 
    .collect() 

更妙的是有函數返回一個Result這表示當發生錯誤:

enum MyError { 
    NotAnInt, 
    TooFewNumbers, 
    TooManyNumbers, 
} 

fn load_into_vec2(file_buf: String) -> Result<Vec<Data>, MyError> { 
    file_buf.lines() 
     .map(|line_iter| { 
      let mut iter = line_iter.split(' ') 
       .map(str::trim) 
       .map(str::parse::<u32>) 
       .fuse(); 

      match (iter.next(), iter.next(), iter.next(), iter.next()) { 
       (Some(Ok(t1)), Some(Ok(t2)), Some(Ok(t3)), Some(Ok(t4))) => if iter.next().is_some() { 
        Err(MyError::TooManyNumbers) 
       } else { 
        let mut data_node = Data::new(); 
        data_node.load((t1, t2, t3, t4)); 
        Ok(data_node) 
       }, 
       (None, _, _, _) | 
       (_, None, _, _) | 
       (_, _, None, _) | 
       (_, _, _, None) => Err(MyError::TooFewNumbers), 
       (Some(Err(_)), _, _, _) | 
       (_, Some(Err(_)), _, _) | 
       (_, _, Some(Err(_)), _) | 
       (_, _, _, Some(Err(_))) => Err(MyError::NotAnInt), 
      } 
     }) 
     .collect() 
} 
+0

你知道你不應該在迭代器上多次調用'next'而不檢查每一步或將它融合。 – Shepmaster

+0

你當然是對的。 [我們也應該這樣](https://github.com/Manishearth/rust-clippy/issues/1448) –