Skip to content

常见Trait使用

FromStr

假设你有一个字符串"42",你想要将它解析为i32类型的数字:

rust
let num_str = "42";
let num: i32 = num_str.parse().unwrap();
println!("Parsed number: {}", num);
let num_str = "42";
let num: i32 = num_str.parse().unwrap();
println!("Parsed number: {}", num);

对于自定义类型,如果你想能够使用parse方法将字符串转换为该类型的实例,你需要手动实现FromStr trait。下面是一个简单的例子,展示了如何为自定义类型实现FromStr

rust
use std::str::FromStr;

struct Point {
    x: i32,
    y: i32,
}

impl FromStr for Point {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let parts: Vec<&str> = s.split(',').collect();
        if parts.len() != 2 {
            return Err("Input must be in the format 'x,y'".to_string());
        }
        let x = parts[0].parse::<i32>().map_err(|_| "Invalid integer")?;
        let y = parts[1].parse::<i32>().map_err(|_| "Invalid integer")?;
        Ok(Point { x, y })
    }
}

fn main() {
    let point_str = "3,4";
    let point: Point = point_str.parse().unwrap();
    println!("Parsed point: ({}, {})", point.x, point.y);
}
use std::str::FromStr;

struct Point {
    x: i32,
    y: i32,
}

impl FromStr for Point {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let parts: Vec<&str> = s.split(',').collect();
        if parts.len() != 2 {
            return Err("Input must be in the format 'x,y'".to_string());
        }
        let x = parts[0].parse::<i32>().map_err(|_| "Invalid integer")?;
        let y = parts[1].parse::<i32>().map_err(|_| "Invalid integer")?;
        Ok(Point { x, y })
    }
}

fn main() {
    let point_str = "3,4";
    let point: Point = point_str.parse().unwrap();
    println!("Parsed point: ({}, {})", point.x, point.y);
}

Add

为Point结构体实现Add<Size>特征,以便可以将Point和Size相加:

rust
#[derive(Debug, PartialEq)]
struct Point {
    x: i32,
    y: i32,
}

#[derive(Debug, PartialEq)]
struct Size {
    width: i32,
    height: i32,
}

use std::ops::Add;

impl Add<Size> for Point {
    type Output = Point;

    fn add(self, other: Size) -> Point {
        Point {
            x: self.x + other.width,
            y: self.y + other.height,
        }
    }
}
#[derive(Debug, PartialEq)]
struct Point {
    x: i32,
    y: i32,
}

#[derive(Debug, PartialEq)]
struct Size {
    width: i32,
    height: i32,
}

use std::ops::Add;

impl Add<Size> for Point {
    type Output = Point;

    fn add(self, other: Size) -> Point {
        Point {
            x: self.x + other.width,
            y: self.y + other.height,
        }
    }
}
  • 需要注意的是,谁在前面,谁就要实现Add特征。

  • 如果是 Point + Point 就不需要给Add传泛型参数

Send

  • 一个任务要实现 Send 特征,那它在 .await 调用的过程中所持有的全部数据都必须实现 Send 特征
  • 若实现了 Send 特征(可以在线程间安全地移动),那任务自然也就可以在线程间安全地移动。

Deref 和 DerefMut

在 Rust 中,Deref 和 DerefMut trait 允许重载解引用运算符(*)。通过实现这些 trait,可以自定义当类型被解引用时的行为。这是 Rust 提供的一种智能指针模式,使得自定义类型的行为更接近内建引用。

  • Deref
rust
use std::ops::Deref;

struct MyBox<T>(T);

impl<T> Deref for MyBox<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

fn main() {
    let x = MyBox(5);
    assert_eq!(5, *x); // 使用了Deref trait
}
use std::ops::Deref;

struct MyBox<T>(T);

impl<T> Deref for MyBox<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

fn main() {
    let x = MyBox(5);
    assert_eq!(5, *x); // 使用了Deref trait
}
  • DerefMut
rust
use std::ops::{Deref, DerefMut};

impl<T> DerefMut for MyBox<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

fn main() {
    let mut x = MyBox(5);
    *x = 6; // 使用了DerefMut trait
    assert_eq!(6, *x);
}
use std::ops::{Deref, DerefMut};

impl<T> DerefMut for MyBox<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

fn main() {
    let mut x = MyBox(5);
    *x = 6; // 使用了DerefMut trait
    assert_eq!(6, *x);
}

Rust 会自动使用 DerefDerefMut 来进行类型之间的强制转换,使得函数或方法调用更加灵活。这意味着当你调用一个需要特定引用类型的函数或方法时,如果提供了一个实现了 Deref(或 DerefMut)的类型,Rust 会自动解引用为目标类型。

rust
fn print_str(s: &str) {
    println!("{}", s);
}

fn main() {
    let my_string = MyBox(String::from("Hello, Rust!"));
    print_str(&*my_string); // 显式解引用
    print_str(&my_string);  // 自动解引用强制转换
}
fn print_str(s: &str) {
    println!("{}", s);
}

fn main() {
    let my_string = MyBox(String::from("Hello, Rust!"));
    print_str(&*my_string); // 显式解引用
    print_str(&my_string);  // 自动解引用强制转换
}

如上,MyBox自动解引用会经过以下步骤:

  • 发现你想把一个my_string(MyBox类型)引用转为&str
  • 解引用 *my_string
  • &*my_string 获取引用

ToOwned

它可以把借用的数据克隆出一个拥有所有权的数据。

rust
let s: &str = "a";
let ss: String = s.to_owned();

let v: &[i32] = &[1, 2];
let vv: Vec<i32> = v.to_owned();
let s: &str = "a";
let ss: String = s.to_owned();

let v: &[i32] = &[1, 2];
let vv: Vec<i32> = v.to_owned();