第18回です。
前回はこちら。
[第18回の様子]
2021/11/17に第18回を開催した。
内容としてはRust By Example 日本語版の「6.2. TryFromおよびTryInto」、「6.3. Stringとの型変換」に取り組んだ。
参加者はちょっと増えて、全部で8人。
今日はSlackでの関連発言が活発だった。



[学んだこと]
- 6.2. TryFromおよびTryInto
- From/Intoと似ているが、TryFrom/TryIntoは失敗する可能性のある型変換で利用する
use std::convert::TryFrom;
#[derive(Debug, PartialEq)]
struct EvenNumber(i32);
impl TryFrom<i32> for EvenNumber {
type Error = ();
fn try_from(value: i32) -> Result<Self, Self::Error> {
if value % 2 == 0 {
Ok(EvenNumber(value)) // 偶数だったらOkでEvenNumber型を返す
} else {
Err(()) // 奇数の場合はErrを返す
}
}
}
fn main() {
// TryFrom
assert_eq!(EvenNumber::try_from(8), Ok(EvenNumber(8)));
assert_eq!(EvenNumber::try_from(5), Err(()));
}
- Intoを使うとFromが呼び出されるのと同様、TryIntoを使うとTryFromの実装が呼び出される
let result: Result<EvenNumber, ()> = 8i32.try_into(); // 先ほど使ったtry_from()が呼び出される assert_eq!(result, Ok(EvenNumber(8)));
Result<EvenNumber, ()>を何度も書くのがつらい場合は、前回やったエイリアスを使うと良さそう
type Optional<T> = Result<T, ()>; let result: Optional<EvenNumber> = 8i32.try_into();
- 6.3. Stringとの型変換
- Stringへの変換にはToStringトレイトを実装する必要がある
- ただし、fmt::Displayトレイトを実装すると自動的にToStringトレイトも実装されるのでこちらがおすすめ
use std::fmt;
struct Circle {
radius: i32
}
impl fmt::Display for Circle {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Circle of radius {}", self.radius)
}
}
fn main() {
let circle = Circle { radius: 6 };
println!("{}", circle);
// Circle of radius 6
println!("{}", circle.to_string());
// Circle of radius 6
}
- 文字列から数値への変換はparse()関数を利用する
// 変数側で型を指定する:i32型がFromStrトレイトを実装しているため利用可能 let parsed: i32 = "5".parse().unwrap(); // turbofish構文を利用して型を指定する let turbo_parsed = "10".parse::<i32>().unwrap();
- ここで登場したunwrap()はResult<T, S>から結果を取り出して(unwrapして)くれる:かわりに、以下のように?を使うと、結果を取り出しつつ例外を呼び出しもとに伝えてくれる
type ParseIntResult<T> = Result<T, std::num::ParseIntError>;
fn sum_strs(m: &str, n: &str) -> ParseIntResult<i32> {
let parsed: i32 = m.parse()?;
let turbo_parsed = n.parse::<i32>()?;
Ok(parsed + turbo_parsed)
}
fn main() {
let sum = sum_strs("5", "10");
println!("Sum: {:?}", sum); // Sum: Ok(15)
let sum = sum_strs("a", "10");
println!("Sum: {:?}", sum); // Sum: Err(ParseIntError { kind: InvalidDigit })
}
- 書き方がスッキリしている。これを使いこなせるようになりたい...
- ちなみに、
?演算子を使わずにmatchで愚直に書くと次のようになる。冗長...
fn sum_strs2(m: &str, n: &str) -> ParseIntResult<i32> {
let result_parsed: ParseIntResult<i32> = m.parse();
match result_parsed {
Result::Ok(parsed) => {
let result_turbo_parsed = n.parse::<i32>();
match result_turbo_parsed {
Result::Ok(turbo_parsed) => Ok(parsed + turbo_parsed),
Result::Err(e) => Err(e),
}
},
Result::Err(e) => Err(e),
}
}
[まとめ]
モブプログラミングスタイルでRust dojoを開催した。
Resultと?演算子を使いこなせるようになりたい...!
今週のプルリクエストはこちら。