impl 基础概念
impl 是 "implementation" 的缩写,表示实现。impl 块允许你为一个结构体定义行为,比如函数和方法。它的语法如下:
struct Rectangle {
width: u32,
height: u32,
}
// 使用 impl 为 Rectangle 添加功能
impl Rectangle {
// 方法和关联函数定义在这里
}
实例方法
我们可以使用 impl 为结构体定义方法。这些方法一般会用到 self 参数来访问结构体实例的数据。
示例:为 Rectangle 结构体定义一个计算面积的 area 方法。
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
// 定义一个计算面积的方法
fn area(&self) -> u32 {
self.width * self.height
}
}
fn main() {
let rect1 = Rectangle { width: 30, height: 50 };
println!("The area of the rectangle is {} square pixels.", rect1.area());
}
代码解释:
&self:表示此方法会以不可变引用的方式接收实例。通过self,可以访问结构体的width和height。rect1.area():使用结构体实例rect1调用方法area,Rust 自动识别self代表rect1。
关联函数
关联函数的特点是它们不接收 self 参数。关联函数通常用于定义结构体的 构造函数 或其他无需实例的方法。
示例:为 Rectangle 结构体定义一个关联函数 square,创建一个宽高相等的矩形。
impl Rectangle {
fn square(size: u32) -> Rectangle {
Rectangle { width: size, height: size }
}
}
fn main() {
let sq = Rectangle::square(30);
println!("Square rectangle has width {} and height {}", sq.width, sq.height);
}
代码解释:
Rectangle::square(30):调用关联函数square创建一个新的Rectangle实例。- 关联函数通常通过
结构体名::函数名语法调用。
self 关键字的用法
在方法中,self 可以有三种形式:
self:表示获取实例的所有权,方法中可以修改实例数据。&self:以不可变引用方式访问实例,不能修改实例数据。&mut self:以可变引用方式访问实例,允许修改实例数据。
示例:添加一个方法 resize 修改矩形的大小。
impl Rectangle {
fn resize(&mut self, new_width: u32, new_height: u32) {
self.width = new_width;
self.height = new_height;
}
}
fn main() {
let mut rect1 = Rectangle { width: 30, height: 50 };
rect1.resize(60, 80);
println!("Resized rectangle: width {}, height {}", rect1.width, rect1.height);
}
练习
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
// 一个关联函数
fn new(width: u32, height: u32) -> Rectangle {
Rectangle { width, height }
}
// 一个结构体方法
fn area(&self) -> u32 {
self.width * self.height
}
// 另一个结构体方法
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.height > other.height
}
}
fn main() {
let rect1 = Rectangle::new(30, 50); // 调用关联函数
let rect2 = Rectangle::new(10, 20);
println!("Area of rect1: {}", rect1.area()); // 调用结构体方法
println!("rect1 can hold rect2: {}", rect1.can_hold(&rect2));
}
Q & A
Q: 关联函数与实例方法,差异就在 self 上吗?
A: 是的,关联函数和实例方法的主要差异就在于 self 的使用。
实例方法:接收 self,可以直接访问结构体的字段,强调了与具体实例的绑定
关联函数:不接收 self,用于定义不依赖于特定实例的函数,通常用于构造和静态逻辑。
Q: let area1 = Rectangle::area(&rect); 实例方法也可以通过 结构体名::方法(&实例) 的形式调用, 为什么如此设计?
A: Rust 在设计中追求一致性与对称性。Rust 的方法调用本质上是对 函数调用 的一种封装,将 实例.方法() 形式与 结构体名::方法(&实例) 形式视为对同一方法的不同调用方式。
可以在不同的实例上重复使用该方法,非常适合于通用代码(比如高阶函数或泛型函数).
// 这个函数接受一个闭包或函数作为参数,并调用它来获取面积
fn print_area<F>(rectangle: &Rectangle, area_func: F)
where
F: Fn(&Rectangle) -> u32,
{
let area = area_func(rectangle); // 调用传入的函数计算面积
println!("The area of the rectangle is: {}", area);
}
fn main() {
let rect = Rectangle { width: 30, height: 50 };
// 传入 `Rectangle::area` 作为参数,而不是直接调用 `rect.area()`
print_area(&rect, Rectangle::area);
}
Rectangle::area 的这种形式可以在不绑定具体实例的情况下引用方法。