Rust 基础入门 - 第六章
定义方法
Rust 使用 impl
关键字来定义方法,方法是在结构体或枚举上定义的函数。
impl
== implementation
#![allow(unused)]
fn main() {
struct Circle {
x: f64,
y: f64,
radius: f64,
}
impl Circle {
// new 是 Circle 的关联函数,因为它的第一个参数不是 self,且 new 并不是关键字
// 这种方法往往用于初始化当前结构体的实例
fn new(x: f64, y: f64, radius: f64) -> Circle {
Circle {
x: x,
y: y,
radius: radius,
}
}
// Circle 的方法,&self 表示借用当前的 Circle 结构体
fn area(&self) -> f64 {
std::f64::consts::PI * (self.radius * self.radius)
}
}
}
和其他语言不一样的是,其他面向对象的语言,所有定义都在类中,而 Rust 中,方法的定义是在 impl
块中的,如下图所示。这样数据和使用分离的方式,灵活度更高。
第二个例子:
#[derive(Debug)]
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle { // impl 块
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()
);
}
在这个例子中,定义了一个“矩形”结构体,然后在 impl
块中定义了一个 area
方法,这个方法接收一个 &self
参数,这个参数是一个指向当前实例的引用,这样就可以在方法中使用 self
来访问当前实例的数据。
self、&self、&mut self
在 area
的接受参数中,我们使用 &self
替代 rectangle: &Rectangle
,&self
其实是 self: &Self
的简写(注意大小写)。在一个 impl
块内,Self
指代被实现方法的结构体类型,self
指代此类型的实例,换句话说,self
指代的是 Rectangle
结构体实例,这样的写法会让我们的代码简洁很多,而且非常便于理解:我们为哪个结构体实现方法,那么 self
就是指代哪个结构体的实例。
其中 self
有三种形式,其所有权不同:
self
:值被移动,不可再使用&self
:值的不可变引用&mut self
:值的可变引用
在上面计算面积的例子中,传入的参数是 &self
,这是因为我们只是想读取结构体中的数据,而不需要获取所有权和修改结构体中的数据,所以使用不可变引用即可。
带有多个参数的方法
#![allow(unused)]
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
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 {
width: 30,
height: 50,
};
let rect2 = Rectangle {
width: 10,
height: 40,
};
let rect3 = Rectangle {
width: 60,
height: 45,
};
println!("Can rect1 hold rect2? {}", rect1.can_hold(&rect2));
println!("Can rect1 hold rect3? {}", rect1.can_hold(&rect3));
}
关联函数
定义在 impl
中且没有 self
的函数被称之为关联函数: 因为它没有 self
,因此它是一个函数而不是方法,它又在 impl 中,与结构体紧密关联,因此称为关联函数。
Rust 中有一个约定俗成的规则,使用 new
来作为构造器的名称,出于设计上的考虑,Rust 特地没有用 new
作为关键字
fn main() {
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
fn new(w: u32, h: u32) -> Rectangle {
Rectangle {width: w, height: h}
}
}
}
因为是函数,所以不能用 .
的方式来调用,我们需要用 :: 来调用,例如 let sq = Rectangle::new(3, 3)
;。这个方法位于结构体的命名空间中:::
语法用于关联函数和模块创建的命名空间。
为枚举类型定义方法
也可以为枚举类型定义方法:
#![allow(unused)]
enum Message {
Quit,
Move {x: i32, y: i32},
Write(String),
ChangeColor(i32, i32, i32),
}
impl Message {
fn call(&self) {
// 在这里定义方法体
}
}
fn main() {
let m = Message::Write(String::from("hello"));
m.call();
}