Traits 特征
特征是为未知类型定义的一组方法的集合。
// 定义一个名为 `Greet` 的特征
trait Greet {
// 一个名为 `greet` 的方法
fn greet(&self);
}
// 为 `Person` 结构实现 `Greet` 特征
struct Person {
name: String,
}
impl Greet for Person {
// 为 `Person` 结构实现 `greet` 方法
fn greet(&self) {
println!("Hello, my name is {}!", self.name);
}
}
fn main() {
let person = Person {
name: String::from("Alice"),
};
// 在 `person` 实例上调用 `greet` 方法
person.greet();
}
Derive (获得)
编译器能够通过 #[derive]
属性为一些特征提供基本实现。
以下是可获得的一些特征列表:
- 比较特征:
Eq
,PartialEq
,Ord
,PartialOrd
. Clone
,用于从&T
创建T
。Copy
,提供类型的“复制语义”而不是“移动语义”。Hash
,用于从&T
计算哈希值。Default
,创建数据类型的空实例。Debug
,使用{:?}
格式化值。
#[derive(PartialEq, PartialOrd)]
struct Duration(f64);
#[derive(Debug)]
struct S(i32);
返回特征
Rust 编译器需要知道每个函数的返回类型需要多少空间。这意味着所有的函数都必须返回一个具体的类型。
Rust 在堆上分配内存时尽量明确。因此,如果函数返回一个指向堆上的特征的指针,你需要用 dyn
关键字写出返回类型,例如 Box<dyn Drawable>
。
trait Drawable {
fn draw(&self);
}
struct Circle {
radius: f64,
}
impl Drawable for Circle {
fn draw(&self) {
println!("Drawing a circle with radius {}.", self.radius);
}
}
struct Square {
side_length: f64,
}
impl Drawable for Square {
fn draw(&self) {
println!("Drawing a square with side length {}.", self.side_length);
}
}
fn get_shape(is_circle: bool) -> Box<dyn Drawable> {
if is_circle {
Box::new(Circle { radius: 5.0 })
} else {
Box::new(Square { side_length: 8.0 })
}
}
fn main() {
let shape1 = get_shape(true);
let shape2 = get_shape(false);
shape1.draw();
shape2.draw();
}
运算符重载
在 Rust 中,许多运算符可以通过特征进行重载。
use std::ops::Add;
#[derive(Debug)]
struct Point {
x: i32,
y: i32,
}
impl Add for Point {
type Output = Point;
fn add(self, other: Point) -> Point {
Point {
x: self.x + other.x,
y: self.y + other.y,
}
}
}
fn main() {
let point1 = Point { x: 1, y: 2 };
let point2 = Point { x: 3, y: 4 };
let result = point1 + point2;
println!("Result: {:?}", result);
// Result: Point { x: 4, y: 6 }
}
Drop
Drop
特征只有一个方法:drop
,它在对象超出作用域时自动调用。
Drop
特征的主要用途是释放实现者实例所拥有的资源。
struct CustomResource {
data: String,
}
impl Drop for CustomResource {
fn drop(&mut self) {
println!("Dropping CustomResource with data: {}", self.data);
}
}
fn main() {
let resource = CustomResource {
data: String::from("learning on literank.com"),
};
println!("Using the CustomResource");
// 在此块的末尾,`resource` 将超出作用域,
// 并自动调用 `drop` 方法。
}
迭代器
Iterator
特征用于在集合(如数组)上实现迭代器。
struct Counter {
current: usize,
end: usize,
}
impl Iterator for Counter {
type Item = usize;
// 定义 `next` 方法,它返回序列中的下一个值
fn next(&mut self) -> Option<Self::Item> {
if self.current < self.end {
let result = Some(self.current);
self.current += 1;
result
} else {
None
}
}
}
fn main() {
let counter = Counter { current: 0, end: 5 };
// 使用 `for` 循环与迭代器一起遍历值
for num in counter {
println!("Count: {}", num);
}
// 你还可以使用 `Iterator` 特征提供的其他方法
let squares: Vec<usize> = Counter { current: 0, end: 5 }
.map(|x| x * x)
.collect();
println!("Squares: {:?}", squares);
}
impl Trait
impl Trait
可以在两种情况下使用:
- 作为参数类型
- 作为返回类型
作为参数类型
trait Printer {
fn print(&self);
}
fn print_shape(shape: impl Printer) {
shape.print();
}
作为返回类型
trait Shape {
fn area(&self) -> f64;
}
struct Circle {
radius: f64,
}
impl Shape for Circle {
fn area(&self) -> f64 {
std::f64::consts::PI * self.radius * self.radius
}
}
fn create_shape() -> impl Shape {
Circle { radius: 3.0 }
}
fn main() {
let shape = create_shape();
println!("Area: {}", shape.area());
}
Clone (克隆)
处理资源时,默认行为是将它们在赋值或函数调用期间传递。然而,有时你需要复制资源。
Clone
特征就用于此场景。
#[derive(Debug, Clone)]
struct Person {
name: String,
age: u32,
}
fn main() {
let person1 = Person {
name: String::from("Alice"),
age: 20,
};
// 克隆 `Person` 实例以创建新实例
let person2 = person1.clone();
// 打印原始和克隆的人物
println!("Original Person: {:?}", person1);
// Original Person: Person { name: "Alice", age: 20 }
println!("Cloned Person: {:?}", person2);
// Cloned Person: Person { name: "Alice", age: 20 }
}
Super Trait(超特征)
Rust 没有"继承",但你可以将一个特征定义为另一个特征的"超特征"。
trait Printable {
fn print(&self);
}
// 定义一个名为 `DebugPrintable` 的子特征,扩展了 `Printable`
trait DebugPrintable: Printable {
fn debug_print(&self);
}
// 为 `Circle` 结构实现 `Printable` 特征
struct Circle {
radius: f64,
}
impl Printable for Circle {
fn print(&self) {
println!("Printing a circle with radius {}", self.radius);
}
}
// 为 `Circle` 结构实现 `DebugPrintable` 特征
impl DebugPrintable for Circle {
fn debug_print(&self) {
println!("Debug printing a circle with radius {}", self.radius);
}
}
fn main() {
// 创建 `Circle` 的实例
let circle = Circle { radius: 3.0 };
// 调用两个特征的方法
circle.print(); // Printing a circle with radius 3
circle.debug_print(); // Debug printing a circle with radius 3
}
代码挑战
尝试修改编辑器中提供的代码以使用特征进行操作。
Loading...
> 此处输出代码运行结果