Rust类型转换

AsRef 和 AsMut

用于类型间廉价引用转换的Trait,为不同类型的引用提供了一种统一的访问方式

AsRef

pub trait AsRef<T: ?Sized> {
    fn as_ref(&self) -> &T;
}

作用: 将某个类型的不可变引用转换为目标类型T的不可变引用
表示当前类型可以视为某种T类型的引用,转换过程无副作用,直接取内部引用,不拷贝数据

常用于函数参数中接受多种类型输入, 例如同时兼容string和&str

// 接受所有能转换为 &str 的类型
fn print_length(s: impl AsRef<str>) {
    println!("Length = {}", s.as_ref().len());
}

fn main() {
    print_length("hello");      // &str
    print_length(String::from("world")); // String
}

标准库实现举例
String: AsRef:String 可以转换为 &str
Vec: AsRef<[T]>:Vec 可以转换为切片 &[T]
PathBuf: AsRef:PathBuf 转换为 &Path

AsMut

pub trait AsMut<T: ?Sized> {
    fn as_mut(&mut self) -> &mut T;
}

作用:将某个类型的可变引用转换为目标类型T的可变引用,常用于需要修改内部数据的场景

fn clear_buffer(buffer: &mut impl AsMut<[u8]>) {
    buffer.as_mut().fill(0); // 将缓冲区全部置零
}

fn main() {
    let mut vec = vec![1u8, 2, 3];
    clear_buffer(&mut vec);    // 修改 Vec<u8>
    clear_buffer(&mut [4u8, 5]); // 修改数组切片
}

标准库实现举例
String: AsMut:String 的可变引用转为 &mut str
Vec: AsMut<[T]>:Vec 的可变引用转为 &mut [T]

From

From是一个用于类型间安全、显示转换的核心trait,定义了一种值到值的转换方式。允许开发者将一种类型转换为另一种类型,同时确保转换的可靠性和所有权转移的清晰性。

pub trait From<T> {
    fn from(value: T) -> Self;
}

作用:将类型T的值转换为当前类型的值,表示一种无损且可靠的转换,通常是直接的构造或简单的数据重组。
关键特性:所有权转移,转换过程中会移动原始值,显示调用,需要显示调用from方法或使用Into trait的自动推导,鼓励高效实现,但运行必要的数据拷贝。

struct Meters(f64);
struct Millimeters(f64);

impl From<Meters> for Millimeters {
    fn from(m: Meters) -> Self {
        Millimeters(m.0 * 1000.0)
    }
}

let meters = Meters(2.5);
let millimeters = Millimeters::from(meters);

String::from(&str):将字符串切片 &str 转换为 String。
Vec::from(&[T]):将切片 &[T] 转换为 Vec
Option::from(value):将值包装为 Some(value)。
基本数值类型之间的转换(如 i32 → i64)。

From和Into的关系

From和Into是互为逆操作的trait

pub trait Into<T> {
    fn into(self) -> T;
}

#[derive(Debug)]
struct Meters(f64);
struct Millimeters(f64);

impl From<Meters> for Millimeters {
    fn from(m: Meters) -> Self {
        Millimeters(m.0 * 1000.0)
    }
}

// 自动获得 Into<Millimeters> 的实现
let meters = Meters(2.5);
let millimeters: Millimeters = meters.into();
println!("{:?}", millimeters); // Millimeters(2500.0)


// 接受任何可转换为 Millimeters 的类型
fn print_length<T: Into<Millimeters>>(value: T) {
    let mm = value.into();
    println!("Length: {} mm", mm.0);
}

print_length(Meters(3.0)); // 直接传入 Meters 类型
print_length(Millimeters(500.0)); // 也可传入 Millimeters 自身

如果类型U实现了From, 则T自动获得Into的实现

错误处理中的应用

From trait 在错误处理中尤为重要,它允许将底层错误类型转换为自定义错误类型,简化 ? 运算符的使用

#[derive(Debug)]
enum MyError {
    Io(std::io::Error),
    Parse(std::num::ParseIntError),
}

impl From<std::io::Error> for MyError {
    fn from(e: std::io::Error) -> Self {
        MyError::Io(e)
    }
}

impl From<std::num::ParseIntError> for MyError {
    fn from(e: std::num::ParseIntError) -> Self {
        MyError::Parse(e)
    }
}

fn read_file() -> Result<String, MyError> {
    let content = std::fs::read_to_string("file.txt")?; // 自动调用 MyError::from(io::Error)
    let _num: i32 = content.parse()?;                   // 自动调用 MyError::from(ParseIntError)
    Ok(content)
}

FromStr

FromStr是永远将字符串解析为特定类型的核心工具,表示一种可能是吧的解析操作

pub trait FromStr {
    type Err; // 关联类型,表示可能的错误类型
    fn from_str(s: &str) -> Result<Self, Self::Err>;
}

rust为所有实现了FromStr的类型提供了parse方法

use std::str::FromStr;

let num = i32::from_str("42").unwrap(); // 42
let flag = bool::from_str("true").unwrap(); // true

let num: i32 = "42".parse().unwrap(); // 等价于 from_str
let pi: f64 = "3.14".parse().unwrap();

TryFrom

TryFrom是Rust标准库中定义的一个trait,用于表示可能失败的类型转换,是From的 安全提到方案。

pub trait TryFrom<T>: Sized {
    type Error;
    fn try_from(value: T) -> Result<Self, Self::Error>;
}

实现 TryFrom 会自动获得对应的 TryInto 实现
二者关系类似 From/Into

use std::convert::TryFrom;

fn main() {
    let big_num = 300i32;
    
    // 将 i32 转换为 u8(可能失败)
    match u8::try_from(big_num) {
        Ok(n) => println!("转换成功: {}", n),
        Err(_) => println!("数值溢出!300 > u8::MAX(255)"),
    }
}
posted @ 2025-05-14 22:21  店里最会撒谎白玉汤  阅读(97)  评论(0)    收藏  举报