最近笔者在学 Rust,被 Rust 中精巧的设计深深吸引,尤其是 traits。它不仅能够应用到 Struct、Enum等,而且还能作为参数传入函数。 应用于结构体 先看这个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 trait Shape { fn area (&self ) -> f64 ; fn perimeter (&self ) -> f64 ; }struct Circle { radius: f64 , }struct Rectangle { width: f64 , height: f64 , }impl Shape for Circle { fn area (&self ) -> f64 { std::f64 ::consts::PI * self .radius * self .radius } fn perimeter (&self ) -> f64 { 2.0 * std::f64 ::consts::PI * self .radius } }impl Shape for Rectangle { fn area (&self ) -> f64 { self .width * self .height } fn perimeter (&self ) -> f64 { 2.0 * (self .width + self .height) } }fn main () { let circle = Circle { radius: 5.0 }; let rectangle = Rectangle { width: 4.0 , height: 6.0 }; println! ("Circle Area: {}, Perimeter: {}" , circle.area (), circle.perimeter ()); println! ("Rectangle Area: {}, Perimeter: {}" , rectangle.area (), rectangle.perimeter ()); }
这个例子是一个很简单的例子,就是将 trait 应用在具体的 Struct 上。类似的还有Enum。如果这就是 traits 的全部,那么 traits 将不值一提。
作为函数参数 看这个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 trait Shape { fn area (&self ) -> f64 ; fn perimeter (&self ) -> f64 ; }fn print_shape_info <T: Shape>(shape: &T) { println! ("Area: {}, Perimeter: {}" , shape.area (), shape.perimeter ()); }fn main () { let circle = Circle { radius: 5.0 }; let rectangle = Rectangle { width: 4.0 , height: 6.0 }; println! ("Circle:" ); print_shape_info (&circle); println! ("Rectangle:" ); print_shape_info (&rectangle); }
这里的函数 print_shape_info
接受一个泛型,但是函数签名对这个泛型做出了限制<T: Shape>
:要求这个泛型实现了Shape traits。
这意味着,随便定义一个类型,只要给这个类型加一个特征,比如 Display,那么这个类型就能使用所有可以接受 Display 的方法。
比如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 use std::fmt; #[derive(Debug)] struct Point { x: i32 , y: i32 , }impl fmt ::Display for Point { fn fmt (&self , f: &mut fmt::Formatter<'_ >) -> fmt::Result { write! (f, "({}, {})" , self .x, self .y) } }fn main () { let p = Point { x: 10 , y: 20 }; println! ("Point p: {}" , p); let message = format! ("The point is: {}" , p); println! ("{}" , message); }
甚至,在这个例子中,实现了 Display
的类型 自动 实现了 ToString
特征,而 to_string()
方法是由 ToString
特征提供的。
ToString
的自动实现 (Blanket Implementation): Rust 标准库为所有实现了 Display
特征的类型,自动提供了一个 ToString
特征的实现 (blanket implementation)。 这个 blanket implementation 大致是这样的 (简化版):
1 2 3 4 5 impl <T: fmt::Display> ToString for T { fn to_string (&self ) -> String { format! ("{}" , self ) } }