- Rust Programming By Example
- Guillaume Gomez Antoni Boucher
- 691字
- 2021-07-02 19:13:07
Reading formatted data from files
As you will certainly have guessed at this point, we'll use iterators once again. This is what the loading function will look like:
fn line_to_slice(line: &str) -> Vec<u32> { line.split(" ").filter_map(|nb| nb.parse::<u32>().ok()).collect() } fn load_highscores_and_lines() -> Option<(Vec<u32>, Vec<u32>)> { if let Ok(content) = read_from_file("scores.txt") { let mut lines = content.splitn(2, "\n").map(|line|
line_to_slice(line)).collect::<Vec<_>>(); if lines.len() == 2 { let (number_lines, highscores) = (lines.pop().unwrap(),
lines.pop().unwrap()); Some((highscores, number_lines)) } else { None } } else { None }
}
Once again, not easy to understand, at first sight. So let's explain all this!
fn line_to_slice(line: &str) -> Vec<u32> {
Our line_to_slice() function does the opposite of slice_to_string(); it transforms a &str into a slice of u32 (or &[u32]). Let's see the iterator now:
line.split(" ").filter_map(|nb| nb.parse::<u32>().ok()).collect()
Just like last time, let's split the calls:
line.split(" ") .filter_map(|nb| nb.parse::<u32>().ok()) .collect()
A bit better! Now let's explain:
line.split(" ")
We create an iterator that will contain all strings between spaces. So a b will contain a and b:
.filter_map(|nb| nb.parse::<u32>().ok())
This method is particularly interesting since it's the merge of two others: filter() and map(). We already know map() but what about filter()? If the condition isn't verified (so if the returned value of the closure is false), the iterator won't pass the value to the next method call. filter_map() works the same at this point: if the closure returns None, the value won't be passed to the next method call.
Now let's focus on this part:
nb.parse::<u32>().ok()
Here, we try to convert &str into u32. The parse() method returns a Result but the filter_map() expects an Option so we need to convert it. That's what the ok() method is for! If your Result is an Ok(value), then it'll convert it into a Some(value). However, if it's an Err(err), it'll convert it into a None (but you'll lose the error value).
To sum this up, this whole line tries to convert a &str into a number and ignores it if the conversion fails so it's not added to our final Vec. Amazing how much we can do with such small code!
And finally:
.collect()
We collect all the successful conversions into a Vec and return it.
That's it for this function, now let's look at the other one:
fn load_highscores_and_lines() -> Option<(Vec<u32>, Vec<u32>)> {
Here, if everything went fine (if the file exists and has two lines), we return an Option containing in the first position the highest scores and in the second position the highest number of lines:
if let Ok(content) = read_from_file("scores.txt") {
So if the file exists and we can get its content, we parse the data:
let mut lines = content.splitn(2, "\n").map(|line|
line_to_slice(line)).collect::<Vec<_>>();
Another iterator! As usual, let's rewrite it a bit:
let mut lines = content.splitn(2, "\n") .map(|line| line_to_slice(line)) .collect::<Vec<_>>();
I think you're starting to get how they work, but just in case you don't know, here's how:
content.splitn(2, "\n")
We make an iterator containing at most two entries (because of the 2 as the first argument) splitting lines:
.map(|line| line_to_slice(line))
We transform each line into a Vec<u32> by using the function described in the preceding code:
.collect::<Vec<_>>();
And finally, we collect those Vecs into a Vec<Vec<u32>>, which should only contain two entries.
Let's look at the next line now:
if lines.len() == 2 {
As said before, if we don't have two entries inside our Vec, it means something is wrong with the file:
let (number_lines, highscores) = (lines.pop().unwrap(),
lines.pop().unwrap());
In case our Vec has two entries, we can get the corresponding values. Since the pop method removes the last entry of the Vec, we get them in reverse (even though we return high scores first then the highest number of lines):
Some((highscores, number_lines))
Then everything else is just the error handling. As we said previously, if any error occurs, we return None. In this case, it's not really important to handle the error since it's just high scores. If we have errors with the sdl libraries, nothing will work as expected, so we need to handle them to avoid a panic.
It's now time to really start the game!
- 普通高校中文學(xué)科基礎(chǔ)教材古典文獻(xiàn)學(xué)基礎(chǔ)
- 單讀. 十周年特輯(時間的移民+在世界的門外)共2冊
- 國外圖書館動漫資源建設(shè)與服務(wù)
- 檔案庫房技術(shù)管理
- 檔案利用與服務(wù)
- 大數(shù)據(jù)環(huán)境下高校圖書館知識服務(wù)模式研究
- 云環(huán)境下我國綜合數(shù)字檔案館建設(shè)模式研究
- 圖書情報與圖書館服務(wù)探究
- 魯迅輯校古籍考
- 中國人民大學(xué)復(fù)印報刊資料轉(zhuǎn)載指數(shù)排名研究報告2018(中國人民大學(xué)研究報告系列)
- 中國人民大學(xué)復(fù)印報刊資料轉(zhuǎn)載指數(shù)排名研究報告2017
- 李一氓文存(第三卷):題跋·詩聯(lián)·劇本
- 金開誠文選
- 浩蕩游絲:何焯與清代的批校文化(精裝)
- 圖書館學(xué)研究法:學(xué)術(shù)論文寫作摭要