https://www.rustfinity.com/advent-of-rust
↑をやってみる
❗ネタバレ注意
Day1
attach_message_to_present() へ所有権を移しているので、 main() の println!() マクロでメッセージを出力できない→ clone() して、新たにヒープにメモリ確保しようというものだった
しかし、これはベストプラクティスではないと言う話、、、
pub fn main() {
let gift_message = String::from("Merry Christmas! Enjoy your gift!");
attach_message_to_present(gift_message.clone());
println!("{}", gift_message);
}
// Don't change this function!
pub fn attach_message_to_present(message: String) {
println!("The present now has this message: {}", message);
}
Day2 - Memory doesn’t grow on Christmas trees 🎄
Day1 の、新しく clone() する方法はベストプラクティスではないという話から、ではどうすればいいのかという話へ
clone() では新しくメモリに確保していたが、そうではなく参照を渡してあげれば解決する問題であった
→ &str を渡すことに
pub fn main() {
let gift_message = String::from("Merry Christmas! Enjoy your gift!");
attach_message_to_present(&gift_message);
println!("{}", gift_message);
}
pub fn attach_message_to_present(message: &str) {
println!("The present now has this message: {}", message);
}
Day3: Restoring the Nice List
(タイトルに統一感ないの気になるな)
Day3 は、型キャストの話だった
f32 (符号あり小数点あり) と u32 (符号なし)を計算するために as を使用した
// We need to find the nice and naughty kids for santa
// Each good deed is worth 1 point and each bad deed is worth 2 points
pub const GOOD_WEIGHT: f32 = 1.0;
pub const BAD_WEIGHT: f32 = 2.0;
pub fn is_nice(good_deeds: u32, bad_deeds: u32) -> bool {
if good_deeds == 0 && bad_deeds == 0 {
return false;
}
let good_score = good_deeds as f32 * GOOD_WEIGHT;
let bad_score = bad_deeds as f32 * BAD_WEIGHT;
let total_score = good_score / (good_score + bad_score);
return total_score >= 0.75;
}
Day 4: Structifying the Naughty List
だんだんボリューミーになってきた
やること
- Add two variants to the Niceness enum: Nice and Naughty. Nice takes the number of good deeds.
- Add two fields to the Kid struct: name of type String and niceness of type Niceness.
- Move the is_nice function we created on Day 3 to an associated function of the Kid struct.
- Finally, implement the new() associated function for the Kid struct.
Niceness を enum で定義し、Kid のコンストラクタで is_nice() を判定し、 enum を埋めて返すというもの
追加で、 is_nice() 関数を、 Kid の関連関数としてまとめている
pub const GOOD_WEIGHT: f32 = 1.0;
pub const BAD_WEIGHT: f32 = 2.0;
#[derive(Debug, PartialEq)] // needed for tests
pub enum Niceness {
Nice(u32),
Naughty,
}
pub struct Kid {
pub name: String,
pub niceness: Niceness,
}
impl Kid {
fn is_nice(good_deeds: u32, bad_deeds: u32) -> bool {
if good_deeds == 0 && bad_deeds == 0 {
return false;
}
let good_deeds = good_deeds as f32 * GOOD_WEIGHT;
let bad_deeds = bad_deeds as f32 * BAD_WEIGHT;
let ratio = good_deeds / (good_deeds + bad_deeds);
ratio >= 0.75
}
pub fn new(name: String, good_deeds: u32, bad_deeds: u32) -> Kid {
if Self::is_nice(good_deeds, bad_deeds) {
return Self{
name,
niceness: Niceness::Nice(good_deeds),
};
} else {
return Self{
name,
niceness: Niceness::Naughty,
};
}
}
}
Day 5: Parsing naughty-list.csv
初めて使ったメソッドがいろいろあったのでまとめる
.next()
イテレータを進め、次の値を返す。返す値は Some()
ok_or()
Transforms the Option
.parse::<T>()
Parses this string slice into another type.
型を指定してパースする
let four: u32 = "4".parse().unwrap(); // これだと危なくない?
assert_eq!(4, four);
let four = "4".parse::<u32>(); // こうすると Some にしてくれる?
assert_eq!(Ok(4), four);
xxx()?: ? 演算子
https://zenn.dev/hakoten/articles/8ae9dd0d3a2080#%3F-%E6%BC%94%E7%AE%97%E5%AD%90
?演算子は、Resultを簡単に扱うための構文糖衣で、関数がResult型を返す場合、?を使うことでエラーが発生したら早期にその関数からリターンすることができる。
.map_err()
? 演算子は同じErrのみ返せるが、エラーの型が違うと同じ返り値として使えないので、 err を変換するというもの
今回は返り値が &'static str だが、 parse::<u32>() の Err は ParseIntErr だったので、文字列のエラーに変換した
Answer
pub const GOOD_WEIGHT: f32 = 1.0;
pub const BAD_WEIGHT: f32 = 2.0;
#[derive(Debug, PartialEq)]
pub enum Niceness {
Nice(u32),
Naughty,
}
pub struct Kid {
pub name: String,
pub niceness: Niceness,
}
const NONE_FIELD_ERR: &str = "None Feild.";
const PARSE_ERR: &str = "Could not Parse";
impl Kid {
pub fn parse_row(csv_row: &str) -> Result<Kid, &'static str> {
let mut fields = csv_row.split(',');
let name = fields.next().ok_or(NONE_FIELD_ERR)?.to_string();
let good_deeds = fields.next().ok_or(NONE_FIELD_ERR)?.parse::<u32>().map_err(|_| PARSE_ERR)?;
let bad_deeds = fields.next().ok_or(NONE_FIELD_ERR)?.parse::<u32>().map_err(|_| PARSE_ERR)?;
Ok(Self::new(name, good_deeds, bad_deeds))
}
pub fn new(name: String, good_deeds: u32, bad_deeds: u32) -> Self {
let niceness = if Self::is_nice(good_deeds, bad_deeds) {
Niceness::Nice(good_deeds)
} else {
Niceness::Naughty
};
Self { name, niceness }
}
pub fn is_nice(good_deeds: u32, bad_deeds: u32) -> bool {
if good_deeds == 0 && bad_deeds == 0 {
return false;
}
let good_deeds = good_deeds as f32 * GOOD_WEIGHT;
let bad_deeds = bad_deeds as f32 * BAD_WEIGHT;
let ratio = good_deeds / (good_deeds + bad_deeds);
ratio >= 0.75
}
}