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