Rust 基本文法 - From、TryFrom -
はじめに
Rust を使っていく中で、From、TryFrom を実装する機会がありました。
初見ではなんのこっちゃ理解できなかったので、同じく躓く方もいらっしゃるのではないでしょうか。
コードは Rust Playground でも試すことができますので、もし宜しければ手を動かしてみてください。
From について
Fromでは、Aの型をBの型に変換することが可能です。
以下の例のように struct Number
で impl From<T> for T
を実装します。
※Rust 公式ドキュメントからの引用です。
#[derive(Debug)]
struct Number {
value: i32,
}
impl From<i32> for Number {
fn from(item: i32) -> Self {
Number { value: item }
}
}
impl From<T>
の T部分にはベースとなる(変換対象の)型を宣言します。
for T
の T部分には変換先の型を指定します。
呼び出し元では、以下のように記述します。
fn main() {
let numa = Number::from(30);
let numb: Number = 30.into();
println!("My number is {:?}", numa);
println!("My number is {:?}", numb);
}
from
もしくはinto
を使って呼び出すことが可能です。
こうすることで、i32
型で渡された値が、自作したNumber
型に変換されます。
impl From<T> for T
を実装しましたが、呼び出し元の呼び出しパターンは2種類あることがわかります。
TryFrom について
TryFrom は From と近いですが、返り値として Result<S>
を返します。
Rusult を返す、ということはつまり、Error が起こりうるということになります。
From では変換処理で Error となることは想定しませんでしたが、TryFrom では Error となることを想定した実装をする必要があります。
どういうことかというと、ドキュメントの内容を見つつ深堀りします。
#[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))
} else {
Err(())
}
}
}
書き方自体は、Fromと同じです。
impl TryFrom<T> for T
のように<T>
には変換元、変換先の型を指定します。
try_from
という関数を実装していますが、先ほど述べたように、Result
が返るように実装されています。
引数で受け付けた、i32
型の値が、2で割り切れる場合のみ、EvenNumber(i32)
に変換するという処理になります。
つまり条件付きの型変換処理ということです。
呼び出し元では、以下のように記述します。
let numa = EvenNumber::try_from(8);
// Result なので match で処理する
match numa {
Ok(num) => println!("Number is {:?}", num),
Err(_) => println!("Number is not even"),
}
let numb: Result<EvenNumber, ()> = 8.try_into();
// Result なので match で処理する
match numb {
Ok(num) => println!("Number is {:?}", num),
Err(_) => println!("Number is not even"),
}
try_from
もしくはtry_into
を使って呼び出すことが可能です。
先ほど紹介した、From の呼び出し方とほとんど変わりません。
Result
なのでエラーハンドリングをしましょう、といった違いくらいです。
おわりに
後だしですが、Rust のドキュメントに From
、TryFrom
はしっかりと書かれています。
実際、Rust を使って開発していると、実装するケースは必ず出てくると思います。
▼ドキュメント
ではではー!
Discussion