rust学习笔记之小练习:类型转换

类型转换

as 运算符

fn average(values: &[f64]) -> f64 {
    let total = values.iter().sum::<f64>();
    total / values.len() as f64
}

fn main() {
    let values = [3.5, 0.3, 13.0, 11.7];
    println!("{}", average(&values)); // 7.125
    
    assert_eq!(average(&[3.5, 0.3, 13.0, 11.7]), 7.125);
}

From 和 Into trait

#[derive(Debug)]
struct Person {
    name: String,
    age: usize,
}

// 实现 Default trait
impl Default for Person {
    fn default() -> Person {
        Person {
            name: String::from("John"),
            age: 30,
        }
    }
}

// 实现 From<&str> trait
impl From<&str> for Person {
    fn from(s: &str) -> Person {
        if s.len()>0 {
            if let Some((name,age))=s.split_once(','){
                if ! name.is_empty(){
                    if let Ok(age)= age.parse::<usize>(){
                        return Self {
                            name:name.to_string(),
                            age
                        };
                    }
                }
            }
        }   
        Self::default()
    }
}

fn main() {
    // 使用 `from` 函数
    let p1 = Person::from("Mark,20");
    assert_eq!(p1.name, "Mark");
    assert_eq!(p1.age, 20);
    // 由于 From 被 Person 实现了,我们应该可以使用 Into
    let p2: Person = "Gerald,70".into();
    assert_eq!(p2.name, "Gerald");
    assert_eq!(p2.age, 70);
    
    let dp = Person::default();
    assert_eq!(dp.name, "John");
    assert_eq!(dp.age, 30);
    
    let vec = vec!["","Mark,twenty","Mark","Mark,",",1",",",",one","Mike,32,","Mike,32,man"];
    for key in vec{
        let p = Person::from(key);
        assert_eq!(dp.name, "John");
        assert_eq!(dp.age, 30);
    }
}

TryFrom 和 TryInto trait

TryFrom 是一个简单和安全的的转换,在某些情况下会以可控方式失败。基本上与 From trait相同,主要的区别是这个返回一个 Result 类型而不是目标类型。

use std::convert::{TryFrom, TryInto};

#[derive(Debug, PartialEq)]
struct Color {
    red: u8,
    green: u8,
    blue: u8,
}

// 这个错误类型用于 `TryFrom` 转换。
#[derive(Debug, PartialEq)]
enum IntoColorError {
    BadLen,// 不正确的切片长度
    IntConversion,// 整数转换错误
}

// 元组实现
impl TryFrom<(i16, i16, i16)> for Color {
    type Error = IntoColorError;
    fn try_from(tuple: (i16, i16, i16)) -> Result<Self, Self::Error> {
      match tuple{
            (r @ 0..=255 , g @ 0..=255, b @ 0..=255)=>{
                Ok(Color{red:r as u8,green:g as u8,blue:b as u8})
            },
            _=>{
                Err(IntoColorError::IntConversion)
            }
        }
    }
}

// 数组实现
impl TryFrom<[i16; 3]> for Color {
    type Error = IntoColorError;
    fn try_from(arr: [i16; 3]) -> Result<Self, Self::Error> {
         match arr{
            [r @ 0..=255 , g @ 0..=255, b @ 0..=255]=>{
                Ok(Color{red:r as u8,green:g as u8,blue:b as u8})
            },
            _=>{
                Err(IntoColorError::IntConversion)
            }
        }
    }
}

// 切片实现
impl TryFrom<&[i16]> for Color {
    type Error = IntoColorError;
    fn try_from(slice: &[i16]) -> Result<Self, Self::Error> {
        if slice.len()==3 {
            match *slice{
                [r @ 0..=255 , g @ 0..=255, b @ 0..=255]=>{
                    Ok(Color{red:r as u8,green:g as u8,blue:b as u8})
                },
                _=>{
                    Err(IntoColorError::IntConversion)
                }
            }
        }else{
            Err(IntoColorError::BadLen)
        }
    }
}

fn main() {
    // 使用 `try_from` 函数
    let c1 = Color::try_from((183, 65, 14));
    println!("{:?}", c1);

    // 由于 TryFrom 被实现于 Color,我们可以使用 TryInto
    let c2: Result<Color, _> = [183, 65, 14].try_into();
    println!("{:?}", c2);

    let v = vec![183, 65, 14];
    // 对于切片我们可以使用 `try_from` 函数
    let c3 = Color::try_from(&v[..]);
    println!("{:?}", c3);
    // 或者用括号包含切片并使用 TryInto
    let c4: Result<Color, _> = (&v[..]).try_into();
    println!("{:?}", c4);
    
    assert_eq!(Color::try_from((256, 1000, 10000)),Err(IntoColorError::IntConversion));
    assert_eq!(Color::try_from((-1, -10, -256)),Err(IntoColorError::IntConversion));
    assert_eq!(Color::try_from((-1, 255, 255)),Err(IntoColorError::IntConversion));
    let c: Result<Color, _> = (183, 65, 14).try_into();
    assert!(c.is_ok());
    assert_eq!(c.unwrap(),Color {red: 183,green: 65,blue: 14});
    
    let c: Result<Color, _> = [1000, 10000, 256].try_into();
    assert_eq!(c, Err(IntoColorError::IntConversion));
    let c: Result<Color, _> = [-10, -256, -1].try_into();
    assert_eq!(c, Err(IntoColorError::IntConversion));
    let c: Result<Color, _> = [-1, 255, 255].try_into();
    assert_eq!(c, Err(IntoColorError::IntConversion));
    let c: Result<Color, _> = [183, 65, 14].try_into();
    assert!(c.is_ok());
    assert_eq!(c.unwrap(),Color {red: 183,green: 65,blue: 14});
    
    let arr = [10000, 256, 1000];
    assert_eq!(Color::try_from(&arr[..]),Err(IntoColorError::IntConversion));
    let arr = [-256, -1, -10];
    assert_eq!(Color::try_from(&arr[..]),Err(IntoColorError::IntConversion));
    let arr = [-1, 255, 255];
    assert_eq!(Color::try_from(&arr[..]),Err(IntoColorError::IntConversion));
    let v = vec![183, 65, 14];
    let c: Result<Color, _> = Color::try_from(&v[..]);
    assert!(c.is_ok());
    assert_eq!(c.unwrap(),Color {red: 183,green: 65,blue: 14});
    
    let v = vec![0, 0, 0, 0];
    assert_eq!(Color::try_from(&v[..]), Err(IntoColorError::BadLen));
    let v = vec![0, 0];
    assert_eq!(Color::try_from(&v[..]), Err(IntoColorError::BadLen));
}

FromStr trait

实现了 FromStr 的类型,可以用字符串使用 parse 方法来生成一个实现者类型的对象。parse 方法返回 Result<T,E> 类型。

use std::num::ParseIntError;
use std::str::FromStr;

#[derive(Debug, PartialEq)]
struct Person {
    name: String,
    age: usize,
}

// 错误类型于 `FromStr` 实现。
#[derive(Debug, PartialEq)]
enum ParsePersonError {
    Empty,// 空的输入字符串
    BadLen,// 不正确的字段数
    NoName,// 空的 name 字段
    ParseInt(ParseIntError),// 包装来自 parse::<usize>() 的错误
}

// 实现 FromStr trait
impl FromStr for Person {
    type Err = ParsePersonError;
    fn from_str(s: &str) -> Result<Person, Self::Err> {
        if s.len()>0 {
            let vec:Vec<&str>=s.split(',').collect();
            if let [name,age]=&vec[..]{
                if ! name.is_empty(){
                    return match age.parse::<usize>(){
                       Ok(age)=> Ok(Self {
                            name:name.to_string(),
                            age
                        }),
                        Err(error)=>Err(ParsePersonError::ParseInt(error)), 
                    };
                }else{
                    return Err(ParsePersonError::NoName); 
                }
            }else{
                return Err(ParsePersonError::BadLen); 
            }
        }   
        Err(ParsePersonError::Empty)
    }
}

fn main() {
    let p = "Mark,20".parse::<Person>().unwrap();
    println!("{:?}", p);
    
    let p = "John,32".parse::<Person>();
    assert!(p.is_ok());
    let p = p.unwrap();
    assert_eq!(p.name, "John");
    assert_eq!(p.age, 32);
    
    assert_eq!("".parse::<Person>(), Err(ParsePersonError::Empty));
    assert!(matches!("John,".parse::<Person>(),Err(ParsePersonError::ParseInt(_))));
    assert!(matches!("John,twenty".parse::<Person>(),Err(ParsePersonError::ParseInt(_))));
    assert_eq!("John".parse::<Person>(), Err(ParsePersonError::BadLen));
    assert_eq!(",1".parse::<Person>(), Err(ParsePersonError::NoName));
    assert!(matches!(",".parse::<Person>(),Err(ParsePersonError::NoName | ParsePersonError::ParseInt(_))));
    assert!(matches!(",one".parse::<Person>(),Err(ParsePersonError::NoName | ParsePersonError::ParseInt(_))));
    assert_eq!("John,32,".parse::<Person>(), Err(ParsePersonError::BadLen));
    assert_eq!("John,32,man".parse::<Person>(),Err(ParsePersonError::BadLen));
}

AsRef 和 AsMut trait

通过 AsRef trait 实现从一种类型的不可变引用转换为另一种类型的不可变引用。通过 AsMut trait 实现从一种类型的可变引用转换为另一种类型的可变引用。通常用于类型转换。

fn byte_counter<T: AsRef<str>>(arg: T) -> usize {
    arg.as_ref().as_bytes().len()
}

fn char_counter<T: AsRef<str>>(arg: T) -> usize {
    arg.as_ref().chars().count()
}

fn num_sq<T: AsMut<u32>>(arg: &mut T) {
    let p: &mut u32=arg.as_mut();
    *p = *p * *p;
}

fn main() {
    let s = "Café au lait";
    assert_ne!(char_counter(s), byte_counter(s));
    let s = "Cafe au lait";
    assert_eq!(char_counter(s), byte_counter(s));
    let s = String::from("Café au lait");
    assert_ne!(char_counter(s.clone()), byte_counter(s));
    let s = String::from("Cafe au lait");
    assert_eq!(char_counter(s.clone()), byte_counter(s));
    
    let mut num: Box<u32> = Box::new(3);
    num_sq(&mut num);  
    assert_eq!(*num, 9);
}
posted @ 2025-08-01 14:51  carol2014  阅读(10)  评论(0)    收藏  举报