【Rust自学】5.3. struct的方法(Method)

📅 2026/7/23 18:48:20
【Rust自学】5.3. struct的方法(Method)
5.3 struct的方法(Method)5.3.1. 什么是方法(Method)方法和函数类似也是用fn关键字进行声明方法也有名称、参数和返回值。但方法和函数也有不同之处- 方法在struct或枚举或 trait 对象的上下文中定义。- 方法的第一个参数总是self表示方法所属被调用的struct实例类似于 Python 中的self和 JavaScript 中的this。5.3.2. 方法的实际应用接下来还是看例子以上一篇文章 5.2. struct使用例加打印调试信息 的代码为例struct Rectangle { width: u32, length: u32, } fn main() { let rectangle Rectangle{ width: 30, length: 50, }; println!({}, area(rectangle)); } fn area(dim:Rectangle) - u32 { dim.width * dim.length }area这个函数的作用是计算面积但它很特别它只适用于矩形而不适用于其他形状或其他类型。如果后面要加上计算其他图形面积的函数那么area这个名字就会变得含糊。如果改名成rectangle_area又太麻烦因为main里所有调用这个函数的地方也都要改。所以如果能把存储矩形长宽的Rectangle结构体和只能计算矩形面积的area函数结合到一起就是最好的。对于这种需求Rust 提供了“实现”implementation其关键字是impl。后边跟着 struct 名加上一对{}在里面像定义普通函数一样定义方法就行。对于这个例子struct 名就是Rectangle把定义area函数的代码剪贴到{}内即可impl Rectangle { fn area(dim:Rectangle) - u32 { dim.width * dim.length } }但注意这里的代码还不是方法因为方法的第一个参数必须是self。现在的代码叫关联函数下文会讲。这么写是没有问题的但还可以进一步简化。上文中说到了方法的第一个参数总是self所以这里也可以改一下impl Rectangle { fn area(self) - u32 { self.width * self.length } }你当前写的这个方法绑定在谁上self指的就是谁。这个代码中area函数被绑定在Rectangle上所以self就指的是Rectangle。area的参数不用拿走所有权所以在self前面加上表示引用。当然这么改之后main函数里的函数调用也要改——从函数调用改到方法调用实例.方法名(参数)。fn main() { let rectangle Rectangle{ width: 30, length: 50, }; println!({}, rectangle.area()); }rectangle.area()的括号中不写东西是因为area方法在定义时只使用了self作为参数表示这个方法借用了self即rectangle实例的不可变引用。在调用area时你不需要显式地传递这个实例因为方法调用已经隐式地知道self是rectangle。整体代码如下struct Rectangle { width: u32, length: u32, } impl Rectangle { fn area(self) - u32 { self.width * self.length } } fn main() { let rectangle Rectangle{ width: 30, length: 50, }; println!({}, rectangle.area()); }输出:15005.3.3. 如何定义方法在上面的实际应用中已经写过一遍了所以这里就只做总结- 在impl里定义方法- 方法的第一个参数可以是self、self或mut self。可以获得所有权、不可变引用或可变引用这点和其他参数一样。- 方法可以帮助更好地组织代码因为可以把某个类型的方法都放在同一个impl块里面这样就不必在整个代码库里搜索与某个struct相关的行为了。5.3.4. 方法调用的运算符在 C/C 中调用方法有两种运算符--其格式为object-something()。调用指针指向的对象上的方法就使用这一种也就是object为指针时。-.其格式为object.something()。调用对象本身上的方法就使用这种也就是object不为指针是个对象时。而object-something()实际上是语法糖它等同于(*object).something()*表示解引用。两者的流程都是先解引用得到对象再在对象上调用方法。Rust 提供了自动引用/解引用的特性。也就是说在调用方法时Rust 会根据情况自动添加、mut或*以便object可以匹配方法的签名。这点和 Go 语言一样。举个例子下面这两行代码效果相同point1.distance(point2); (point1).distance(point2);Rust 会根据情况自动在point1前加上。5.3.5. 方法的参数方法除了self也可以带其他参数一个或多个都可以。举个例子在 5.3.2 的代码基础上加一个判断矩形是否能容纳下另一个矩形的功能不考虑斜着放也不考虑矩形的长比宽长的情况impl Rectangle { fn can_hold(self, other: Rectangle) - bool { self.width other.width self.length other.length } }逻辑非常好想只要矩形的宽和长都比另一个大就行。然后再在main函数里声明几个Rectangle实例输出比较结果看看有没有问题就行。以下是完整代码struct Rectangle { width: u32, length: u32, } impl Rectangle { fn can_hold(self, other: Rectangle) - bool { self.width other.width self.length other.length } } fn main() { let rect1 Rectangle{ width: 30, length: 50, }; let rect2 Rectangle{ width: 10, length: 40, }; println!({}, rect1.can_hold(rect2)); }输出true5.3.6. 关联函数可以在impl块里定义不把self作为第一个参数的函数叫关联函数不是方法。它不是在实例上调用的但它与这个类型有关联。例如String::from()就是String这个类型上叫做from的关联函数。关联函数通常用于构造器也就是用来创建关联类型的一个实例。比如说在 5.3.2 的代码基础上加一个构建正方形的构造器正方形也是特殊的矩形impl Rectangle { fn square(size: u32) - Rectangle { Rectangle{ width: size, length: size, } } }参数只需要一个因为构造正方形只需要一个边长。在main函数里调用一下这个关联函数试试其格式为类型名::函数名(参数)。以下是完整代码#[derive(Debug)] struct Rectangle { width: u32, length: u32, } impl Rectangle { fn square(size: u32) - Rectangle { Rectangle{ width: size, length: size, } } } fn main() { let square Rectangle::square(10); println!({:?}, square); }输出Rectangle { width: 10, length: 10 }::不仅可以用于关联函数也可以用于模块创建命名空间以后会讲。5.3.7. 多个impl块每个struct允许拥有多个impl块。比如我要把这篇文章里写过的所有方法和关联函数都写到一个代码示例里。可以这么写多个impl块#[derive(Debug)] struct Rectangle { width: u32, length: u32, } impl Rectangle { fn area(self) - u32 { self.width * self.length } } impl Rectangle { fn can_hold(self, other: Rectangle) - bool { self.width other.width self.length other.length } } impl Rectangle { fn square(size: u32) - Rectangle { Rectangle{ width: size, length: size, } } } fn main() { let square Rectangle::square(10); println!({:?}, square); }也可以这么写合在一个impl块里#[derive(Debug)] struct Rectangle { width: u32, length: u32, } impl Rectangle { fn area(self) - u32 { self.width * self.length } fn can_hold(self, other: Rectangle) - bool { self.width other.width self.length other.length } fn square(size: u32) - Rectangle { Rectangle{ width: size, length: size, } } } fn main() { let square Rectangle::square(10); println!({:?}, square); }