100日後にRustをちょっと知ってる人になる: [Day 47]型変換ためのトレイト: From / Into
Day 47 のテーマ
Day 46 では、Rust の型に関して見てみました。どのような型システムをとっているのか、また型を明示的に変換するキャストの仕組みなどについて確認を行いました。
ところでこの型の変換に関してですが、std::convert という型を変換するトレイトを提供しているモジュールがあります。
提供しているトレイト毎に目的が異なった変換を実施します:
この中から From と Into について使い方を確認しておきます。
From トレイト
From トレイトは次の様に定義されています。
pub trait From<T> {
fn from(T) -> Self;
}
この From トレイトは、ある型に対して、別の型からその型を作る方法を定義できるようにするものです。
例えば、str に対して String を作る場合は次のようになります。
let my_str = "my str";
let my_string = String::from(my_str);
また、i32 から自作の Number 型 を作る場合は次のようになります。
struct Number {
value: i32,
}
impl From<i32> for Number {
fn from(item: i32) -> Self {
Number { value: item }
}
}
let num = Number::from(30);
つまり、このような実装ということになります。
impl From<変換元> for 変換先 {
fn from(from: 変換元) -> 変換先 {
}
}
Into トレイト
Into トレイトは次のように定義されています。
pub trait Into<T> {
fn into(self) -> T;
}
この Into は、From トレイトの逆の関係のトレイトになっています。
自作の型に From トレイトが実装されている場合、Into は必要に応じてそれを呼び出します。
struct Number {
value: i32,
}
impl From<i32> for Number {
fn from(item: i32) -> Self {
Number { value: item }
}
}
ここで Into を使用すると以下のように定義が行なえます。
let num: Number = 30.into();
つまり、同じ処理を以下の 2 種類で表わせるということになります。
-
From トレイト
let num = Number::from(30);
-
Into トレイト
let num: Number = 30.into();
Day 47 のまとめ
From と Into が対になっているという説明をよく見かけるのですが、それだけを真に受けると変換の方向を誤解してしまうと思いました。
From と Into により T 型 と U 型の間で相互に変換可能になるのではありません。(はじめ僕もそうなのかと思っていました…)
変換の方向は同じで、T 型 → U 型という変換であることを間違えないように覚えておかないといけないと思います。
どちらも同じひょうげんだとすると、個人的には、From を実装していれば事足りるかなと思いました。
(Into ならではの使いどころはどこなんでしょう…とちょっと考えたい)
Discussion