Open1

Rust Conversion

shuyin02shuyin02

🧭 全体の地図:型変換の4系統

種類 概念 安全性 主な用途
as プリミティブキャスト x as f64 ❗安全でない場合あり 数値変換や生ポインタ変換
From / Into 安全な変換(常に成功) String::from("hi") / "hi".into() ✅常に成功 明示的な型変換
TryFrom / TryInto 失敗するかもしれない変換 u8::try_from(300)? ⚠️失敗の可能性あり 制約付き変換
AsRef / AsMut 参照として借用変換 path.as_ref() ✅安全 汎用関数での借用変換

🧩 1. as:型キャスト(C言語っぽいけど注意!)

asは「コンパイラに型を強制的に変換させる」演算子です。
ただし、安全性保証が弱いため、Rustの他の仕組みよりも“最後の手段”です。

let x = 10u8;
let y = x as u16; // OK: u8 → u16(安全)
let z = 300u16 as u8; // ⚠️ 256を超えるので「切り詰め」される(z = 44)

つまり as は「ビット変換」であって、意味的な保証はしません。
👉 **「絶対成功するけど意味は保証しない」**という立ち位置です。


🪄 2. From / Into:安全に変換するペア

From は「どうやって他の型から作るか」を定義するトレイトです。
Into はその逆方向に動く**糖衣構文(シンタックスシュガー)**です。

let s = String::from("hello"); // From<&str> for String
let s2: String = "hello".into(); // Into<String> for &str

実際、これらは同義です。
標準ライブラリでは「Fromを実装したら自動的にIntoも使える」ようになっています。

💡「常に成功する変換」しか From/Into では扱いません。


⚙️ 3. TryFrom / TryInto:失敗の可能性がある変換

数値など、全ての変換が安全に行えるとは限らないときに使います。

use std::convert::TryFrom;

let n = u8::try_from(255u16)?; // OK
let m = u8::try_from(300u16);  // Err(_) → 失敗!

TryFrom の戻り値は Result<T, E> なので、?演算子で扱えます。
たとえば「文字列→整数」もこれを使っています:

let num = i32::try_from(42u8)?;       // OK
let parsed: i32 = "123".parse()?;     // 実は `FromStr` トレイトの仕組み(次で説明)

📖 4. FromStr:文字列から構造体などを作る

これは "123".parse::<i32>() の裏で動いているトレイトです。

use std::str::FromStr;

let n = i32::from_str("123").unwrap();
let n2: i32 = "123".parse().unwrap(); // 同じ意味!

parse()FromStr のシンタックスシュガー。
TryFrom のように、戻り値は Result<T, E> です。


🪞 5. AsRef / AsMut:参照を借りるための変換

AsRef は「この型を借りて別の参照として見る」ためのトレイト。
汎用的な関数を書くときに使われます。

fn print_path<P: AsRef<std::path::Path>>(path: P) {
    println!("{:?}", path.as_ref());
}

print_path("foo/bar.txt"); // &str → Path
print_path(std::path::Path::new("baz.txt")); // Path → Path

つまり AsRef は「引数の型が違っても、参照を統一的に扱うための仕組み」。

  • From / Intoの変換
  • AsRef / AsMut参照の変換

🧠 まとめ:4パターンの使い分け方

目的 使うもの 特徴
プリミティブ変換(整数→浮動小数など) as 型安全でないこともある
常に成功する変換 From / Into 値の安全な変換
失敗するかもしれない変換 TryFrom / TryInto Resultで返す
借用(参照)を変換したい AsRef / AsMut 汎用関数で便利

🌱 ちょっとした練習問題(おすすめ)

use std::convert::{From, TryFrom};
use std::str::FromStr;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 1. as
    let x = 42u8 as u16;

    // 2. From / Into
    let s1 = String::from("hi");
    let s2: String = "hi".into();

    // 3. TryFrom
    let n = u8::try_from(255u16)?;
    // let fail = u8::try_from(300u16)?; // Err!

    // 4. FromStr
    let num = i32::from_str("123")?;
    let num2: i32 = "123".parse()?;

    // 5. AsRef
    fn print_len<T: AsRef<str>>(s: T) {
        println!("len = {}", s.as_ref().len());
    }
    print_len("abc");
    print_len(String::from("xyz"));

    Ok(())
}