» Rust快速入门 » 1. 基础篇 » 1.7 类型转化

自定义类型转换

在 Rust 中,基本类型可以通过 casting 强制转换 相互转换。然而,自定义类型需要利用特征(traits)来转换。通常的转换一般使用 FromInto 特征。

From 和 Into

From

From 特征允许类型定义如何从另一种类型创建自己。例如,你可以轻松地将 str 转换为 String

let a = "hello";
let b = String::from(a);

你可以为自己的类型定义转换。

use std::convert::From;

#[derive(Debug)]
struct MagicNumber {
    num: i32,
}

impl From<i32> for MagicNumber {
    fn from(value: i32) -> Self { // Self 在这里表示 `MagicNumber` 结构体
        MagicNumber { num: value }
    }
}

fn main() {
    let mn = MagicNumber::from(58);
    println!("{:?}", mn);
    // MagicNumber { num: 58 }
}

Into

Into 特征是 From 特征的互补。

use std::convert::Into;

#[derive(Debug)]
struct MagicNumber {
    num: i32,
}

impl Into<MagicNumber> for i32 {
    fn into(self) -> MagicNumber { // self 在这里表示 `i32`
        MagicNumber { num: self }
    }
}

fn main() {
    let num = 58i32;
    // 此处的类型注解有助于选择使用哪个 `into` 方法
    let mn: MagicNumber = num.into();
    println!("{:?}", mn);
    // MagicNumber { num: 58 }
}

TryFrom 和 TryInto

类似于 FromIntoTryFromTryInto 也是用于在类型之间进行转换的通用特征。但它们可适用于可能失败的转换。

use std::convert::TryFrom;

struct Temperature {
    value: f64,
}

impl TryFrom<f64> for Temperature {
    type Error = &'static str;

    fn try_from(value: f64) -> Result<Self, Self::Error> {
        // 检查温度是否在有效范围内
        if value < -459.67 {
            Err("Temperature is below absolute zero!")
        } else {
            Ok(Temperature { value })
        }
    }
}

fn main() {
    // 尝试从有效的华氏度值创建 Temperature 实例
    let fahrenheit_value = 32.0;
    match Temperature::try_from(fahrenheit_value) {
        Ok(temp) => println!("Temperature in Celsius: {:.2}", (temp.value - 32.0) * 5.0 / 9.0),
        Err(err) => println!("Error: {}", err),
    }
    // 摄氏度温度:0.00

    // 尝试从无效的华氏度值创建 Temperature 实例
    let invalid_value = -500.0;
    match Temperature::try_from(invalid_value) {
        Ok(temp) => println!("Temperature in Celsius: {:.2}", (temp.value - 32.0) * 5.0 / 9.0),
        Err(err) => println!("Error: {}", err),
    }
    // 错误:温度低于绝对零度!
}

你通常不需要直接实现 TryInto 特征,而应优先实现 TryFrom 特征。因为后者提供了更大的灵活性,并且通过标准库中的通用实现加持,可以自动提供 TryInto 的等效实现。

use std::convert::TryFrom;
use std::convert::TryInto;

#[derive(Debug)]
struct Temperature {
    value: f64,
}

impl TryFrom<f64> for Temperature {
    type Error = &'static str;

    fn try_from(value: f64) -> Result<Self, Self::Error> {
        // 检查温度是否在有效范围内
        if value < -459.67 {
            Err("Temperature is below absolute zero!")
        } else {
            Ok(Temperature { value })
        }
    }
}

fn main() {
    let result: Result<Temperature, &'static str> = 58.0_f64.try_into();
    println!("{:?}", result); // Ok(Temperature { value: 58.0 })
}

字符串转换

要将任何类型转换为 String,只需实现 ToString 特征。 不过一般情况下,都建议不要直接实现这个特征,而是实现更方便的 fmt::Display 特征。后者可自动提供 ToString 功效。

use std::fmt;

struct Temperature {
    value: f64,
}

impl fmt::Display for Temperature {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:.2} degrees Celsius", self.value)
    }
}

fn main() {
    let temperature = Temperature { value: 25.0 };
    println!("Current temperature: {}", temperature);
    // Current temperature: 25.00 degrees Celsius
}

要将 String 转换为任何其他类型,需要实现 FromStr 特征。该特征已被标准库中许多类型实现。

pub trait FromStr: Sized {
    type Err;

    // 必需的方法
    fn from_str(s: &str) -> Result<Self, Self::Err>;
}

FromStrfrom_str 方法一般被隐式使用, 被 strparse 方法调用。

如果要在自定义类型上执行此操作,记得实现该特征。

fn main() {
    let a: i32 = "58".parse().unwrap();
    let b = "589".parse::<i32>().unwrap();
    println!("Sum: {:?}", a + b); // Sum: 647
}

unwrap() 返回 ResultOk 值。

::<...> 是 Rust 中的所谓的 "涡轮鱼" 语法,用于显式指定转换的目标类型。

代码挑战

尝试修改编辑器中提供的代码以完成字符串解析。

Loading...
> 此处输出代码运行结果
上页
下页