Rust能力养成系列之(27): 标准库特性(下)

本文详细介绍了如何在 Rust 中实现复数类型,包括添加运算、从元组转换和显示格式化。通过`Add`、`From`和`Display`特性的运用,展示了泛型和类型系统的灵活性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

接着上篇的复数类型实例,搬砖继续。

 

复数类型 下

有经过上一篇的准备,我们看下现在的代码:

// complex/src/lib.rs
 
use std::ops::Add;
#[derive(Default, Debug, PartialEq, Copy, Clone)]
struct Complex<T> {
    // Real part
    re: T,
    // Complex part
    im: T
}
 
impl<T> Complex<T> {
    fn new(re: T, im: T) -> Self {
        Complex { re, im }
    }
}
 
impl<T: Add<T, Output=T>> Add for Complex<T> { 
    type Output = Complex<T>; 
    fn add(self, rhs: Complex<T>) -> Self::Output { 
        Complex { re: self.re + rhs.re, im: self.im + rhs.im } 
    } 
}
 
#[cfg(test)]
mod tests {
    use Complex;
    #[test]
    fn complex_basics() {
        let first = Complex::new(3,5);
        let second: Complex<i32> = Complex::default();
    }
    fn complex_addition() {
        let a = Complex::new(1,-2);
        let b = Complex::default();
        let res = a + b;
        assert_eq!(res, a);
    }
}

让我们深入了解Complex<T>的impl块:

impl<T: Add<T, Output=T> Add for Complex<T>

相比之下,Add的impl块更加复杂,我们仔细看下:

  • impl<T: Add<T, Output=T>部分说的是我们正在为一个泛型类型T实现Add,其中T实现了Add<T, Output=T>。<T, Output=T>部分表示Add trait的实现必须具有相同的输入和输出类型
  • Add for Complex<T>表示我们正在为Complex<T>类型实现Add trait
  • T:Add必须实现Add trait。如果没有,我们就不能对它使用+操作符

然后是From特性。如果我们也可以从内置的原语类型(比如两个元素的元组,其中第一个元素是实部,第二个元素是虚部)构造复数类型,那就方便多了。既然这么说了,其实可以通过实现From trait来做到这一点。这个特性定义了一个from方法,为我们提供了在类型之间进行转换的一般方法。其文档可以在https://doc.rust-lang.org/std/convert/trait.From.html上找到。

以下是该特性的定义:

pub trait From<T> { 
    fn from(self) -> T;
} 

这个定义稍微简单一些,它是一个泛型特性,其中T指定要转换的类型。当我们实现这个时,只需要将T替换为想要实现它的类型,然后就是实现from方法。接着,我们可以在类型上使用该方法。下面是一个实现代码,它将我们的复数数值转换为一个二元元组类型,这是Rust的原生数据类型:

// complex/src/lib.rs
 
// previous code omitted for brevity
 
use std::convert::From;
 
impl<T> From<(T, T)> for Complex<T> { 
    fn from(value: (T, T)) -> Complex<T> { 
        Complex { re: value.0, im: value.1 }
    } 
}
 
// other impls omitted
 
#[cfg(test)]
mod tests {
    
    // other tests
        
     use Complex;
     #[test]
     fn complex_from() {
         let a = (2345, 456);
         let complex = Complex::from(a);
         assert_eq!(complex.re, 2345);
         assert_eq!(complex.im, 456);
     }
}

让我们来看看这条impl部分(7-9行)。这类似Add trait,除了我们不必通过任何特殊的输出类型来约束泛型。第一个<T>是泛型类型T的声明,第二个和第三个是对应的用法,表明复数类型从(T, T)类型进行创建。

最后,为了让用户能够以习惯的数学符号的形式来查看复数类型,需要实现Display特性,相关文档可见https://doc.rust-lang.org/std/fmt/trait.Display.html,下面是该特性的类型签名:

pub trait Display { 
    fn fmt(&self, &mut Formatter) -> Result<(), Error>; 
}

下面的代码显示了Complex<T>类型所实现的Display:

// complex/src/lib.rs
 
// previous code omitted for brevity
 
use std::fmt::{Formatter, Display, Result};
 
impl<T: Display> Display for Complex<T> {
    fn fmt(&self, f: &mut Formatter) -> Result { 
        write!(f, "{} + {}i", self.re, self.im)
    } 
} 
#[cfg(test)]
mod tests {
    
    // other tests
        
    use Complex;
    #[test]
    fn complex_display() {
        let my_imaginary = Complex::new(2345,456);
        println!("{}", my_imaginary);
    }
}

Display特性有一个fmt方法,它接受一个Formatter 类型,我们使用write!宏。与前面一样,因为我们的Complex<T>类型对re和im字段都使用泛型类型,所以我们需要指定它也必须满足Display trait。

运行cargo test -- --nocapture,我们得到以下输出:

https://note.youdao.com/yws/public/resource/66e26175a3f149e7f52971e6a6c7cf30/xmlnote/81A8CD2D9A144797A5D81402E22C3C04/59404

我们可以看到,我们的复杂类型以可读的格式打印为2345 + 456i,所有的测试都是绿色的。

 

结语

到这里,对标准库特性的初步探索告一段落,在下一篇里,我们看下多态(polymorphism)的内容。

 

主要参考和建议读者进一步阅读的文献

https://doc.rust-lang.org/book

Rust编程之道,2019, 张汉东

The Complete Rust Programming Reference Guide,2019, Rahul Sharma,Vesa Kaihlavirta,Claus Matzinger

Hands-On Data Structures and Algorithms with Rust,2018,Claus Matzinger

Beginning Rust ,2018,Carlo Milanesi

Rust Cookbook,2017,Vigneshwer Dhinakaran

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值