Caution
お使いのブラウザはJavaScriptが実行できない状態になっております。
当サイトはWebプログラミングの情報サイトの為、
JavaScriptが実行できない環境では正しいコンテンツが提供出来ません。
JavaScriptが実行可能な状態でご閲覧頂くようお願い申し上げます。
From / Into / TryFrom / TryInto トレイト
Rustの型変換トレイト『From』『Into』『TryFrom』『TryInto』は、型間の変換を標準化します。『From』を実装すると自動的に『Into』も使えるようになります。
構文
use std::convert::TryFrom;
// From トレイトの実装です。
struct Wrapper(i32);
impl From<i32> for Wrapper {
fn from(val: i32) -> Self {
Wrapper(val)
}
}
// From を実装すると Into も自動で使えます。
let w: Wrapper = Wrapper::from(42); // From を使います。
let w: Wrapper = 42.into(); // Into を使います(型注釈で変換先を指定)。
// TryFrom: 失敗する可能性のある変換です(Result を返します)。
impl TryFrom<i32> for Wrapper {
type Error = String;
fn try_from(val: i32) -> Result<Self, Self::Error> {
if val >= 0 {
Ok(Wrapper(val))
} else {
Err(format!("負の値は受け付けません: {}", val))
}
}
}
変換トレイト一覧
| トレイト | 概要 |
|---|---|
| From<T> | 別の型Tから自型に変換します(失敗しない変換)。 |
| Into<U> | 自型から別の型Uに変換します(From<Self> for U を実装すれば自動実装されます)。 |
| TryFrom<T> | 別の型Tから自型への変換を試みます(Result<Self, Error>を返します)。 |
| TryInto<U> | 自型から別の型Uへの変換を試みます(TryFrom の逆)。 |
| AsRef<T> | 自型から&Tへの変換を提供します(コスト0の参照変換)。 |
| AsMut<T> | 自型から&mut Tへの変換を提供します。 |
サンプルコード
use std::convert::TryFrom;
#[derive(Debug)]
struct Celsius(f64);
#[derive(Debug)]
struct Fahrenheit(f64);
// Fahrenheit から Celsius への変換です。
impl From<Fahrenheit> for Celsius {
fn from(f: Fahrenheit) -> Self {
Celsius((f.0 - 32.0) * 5.0 / 9.0)
}
}
// Celsius から Fahrenheit への変換です。
impl From<Celsius> for Fahrenheit {
fn from(c: Celsius) -> Self {
Fahrenheit(c.0 * 9.0 / 5.0 + 32.0)
}
}
// 値の範囲に制約があるNewtype パターンです。
#[derive(Debug)]
struct Percentage(f64);
impl TryFrom<f64> for Percentage {
type Error = String;
fn try_from(value: f64) -> Result<Self, Self::Error> {
if (0.0..=100.0).contains(&value) {
Ok(Percentage(value))
} else {
Err(format!("パーセントは0〜100の範囲です。受け取った値: {}", value))
}
}
}
fn main() {
// From / Into を使います。
let boiling_f = Fahrenheit(212.0);
let boiling_c = Celsius::from(boiling_f);
println!("212°F = {:.1}°C", boiling_c.0);
let freezing_c = Celsius(0.0);
let freezing_f: Fahrenheit = freezing_c.into(); // Into を使います。
println!("0°C = {:.1}°F", freezing_f.0);
// 標準ライブラリのFrom / Into の例です。
let s = String::from("hello"); // From<&str> for String
let s2: String = "world".into(); // Into<String> for &str
println!("{}, {}", s, s2);
let n: i64 = 42_i32.into(); // i32 から i64 への安全な変換です。
println!("i32 -> i64: {}", n);
// TryFrom を使います。
let good = Percentage::try_from(75.0);
let bad = Percentage::try_from(150.0);
println!("75.0 -> {:?}", good); // Ok(Percentage(75.0))
println!("150.0 -> {:?}", bad); // Err(...)
// TryInto も同様に使えます(use std::convert::TryInto が必要)。
use std::convert::TryInto;
let result: Result<Percentage, _> = 50.0_f64.try_into();
println!("50.0 try_into: {:?}", result);
// 文字列へのFrom/Into例です。
let num: i32 = 42;
let s = num.to_string(); // Display から自動実装される ToString
let back: i32 = s.parse().unwrap();
println!("i32 -> String -> i32: {}", back);
}
概要
『From』を実装すると自動的に『Into』も実装されます。これはRustの「From/Into双対性」と呼ばれる仕組みで、変換の実装は『From』だけに書けばよいようになっています。
関数の引数に使う場合、『Into』を受け取ると呼び出し側が変換を意識しなくて済みます。例えば『fn new(name: impl Into<String>)』とすると、『&str』も『String』も渡せる柔軟な関数になります。
トレイトの基本定義は『trait / impl Trait for 型』を参照してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。