方法语法
方法类似于函数:我们使用关键字和
name,它们可以有参数和返回值,并且包含一些代码
当从其他位置调用方法时,将运行该方法。与函数不同,
方法在结构体(或枚举或 trait
object,我们将在第 6 章和第
17),它们的第一个参数是
always ,它表示方法正在创建的结构的实例
召唤。fn
self
定义方法
让我们更改将实例作为参数的函数
,而是在结构体上定义一个方法,如下所示
在示例 5-13 中。area
Rectangle
area
Rectangle
为了在 的上下文中定义函数,我们为 启动一个(实现)块。此块中的所有内容
将与该类型相关联。然后我们将函数
并更改第一个 (在本例中,仅)
参数添加到签名中和正文中的任意位置。在 中,我们调用了函数并作为参数传递
我们可以改用 Method Syntax 来调用实例上的方法。方法语法在实例之后:我们添加一个点,后跟
方法名称、括号和任何参数。Rectangle
impl
Rectangle
impl
Rectangle
area
impl
self
main
area
rect1
area
Rectangle
在 的签名中,我们使用 代替 。
实际上是 的缩写。在一个区块中,
type 是块所针对的类型的别名。方法必须
的第一个参数的 type 为 type,因此 Rust
允许您仅使用第一个参数 Spot 中的 Name 来缩写它。
注意,我们仍然需要使用 in front 的简写来
指示此方法借用实例,就像我们在 中所做的那样。方法可以不可变地获取 , borrow 的所有权,就像我们在这里所做的那样,或者可变地借用,就像它们可以中的任何
other 参数。area
&self
rectangle: &Rectangle
&self
self: &Self
impl
Self
impl
self
Self
self
&
self
Self
rectangle: &Rectangle
self
self
self
我们选择这里的原因与我们在函数中使用的原因相同
version:我们不想获得所有权,我们只想读取
结构,而不是写入它。如果我们想更改已
调用该方法作为该方法功能的一部分,我们将使用 AS
第一个参数。具有一个通过以下方式获取实例所有权的方法
使用 just as 第一个参数很少见;这种技术通常是
当方法转换为其他内容并且您希望
阻止调用方在转换后使用原始实例。&self
&Rectangle
&mut self
self
self
使用方法而不是函数的主要原因,除了
提供方法语法,并且不必在每个
method 的签名,用于组织。我们已经把我们能做的所有事情都投入了
在一个块中指定类型的实例,而不是让未来的用户
的代码中搜索功能
我们提供的库。self
impl
Rectangle
请注意,我们可以选择为方法指定与结构体的
领域。例如,我们可以定义一个同样名为 :Rectangle
width
在这里,我们选择让方法返回 if the value in
实例的 field is greater than and if the value is : 我们可以将同名方法中的字段用于任何目的。在 中,当我们跟在括号后面时,Rust 知道我们指的是
方法。当我们不使用括号时,Rust 知道我们指的是 field .width
true
width
0
false
0
main
rect1.width
width
width
通常(但并非总是)当我们为方法指定与所需的字段相同的名称时 it 只返回字段中的值,不执行任何其他作。像这样的方法 称为 getter,Rust 不会为 struct 自动实现它们 字段。getter 很有用,因为你可以将 field private 的 intent 的 intent 的 字段作为类型的公共 API 的一部分。我们将讨论哪些公共和私人 ,以及如何在章节中将字段或方法指定为 public 或 private 7.
->
运算符在哪里?
在 C 和 C++ 中,使用两种不同的运算符来调用方法:如果直接调用对象上的方法,则使用
在指向对象的指针上调用该方法,并且需要取消引用
指针优先。换句话说,if 是指针,类似于 。.
->
object
object->something()
(*object).something()
Rust 没有等价于 operator 的 operator;相反,Rust 有一个
称为 自动引用 和 取消引用 的功能。调用方法是
Rust 中为数不多的具有此行为的地方之一。->
它是这样工作的:当你用 Rust 调用一个方法
自动添加 , 或 so 匹配
方法。换句话说,以下内容是相同的:object.something()
&
&mut
*
object
#![allow(unused)] fn main() { #[derive(Debug,Copy,Clone)] struct Point { x: f64, y: f64, } impl Point { fn distance(&self, other: &Point) -> f64 { let x_squared = f64::powi(other.x - self.x, 2); let y_squared = f64::powi(other.y - self.y, 2); f64::sqrt(x_squared + y_squared) } } let p1 = Point { x: 0.0, y: 0.0 }; let p2 = Point { x: 5.0, y: 6.5 }; p1.distance(&p2); (&p1).distance(&p2); }
第一个看起来更干净。此自动引用行为有效
因为方法有一个明确的接收器 — .给定接收器
和方法的名称,Rust 可以明确地判断该方法是否是
读取 ()、更改 () 或消耗 ()。事实
Rust 将 Borrow 隐式用于方法接收器是
在实践中使所有权符合人体工程学。self
&self
&mut self
self
具有更多参数的方法
让我们通过在结构体上实现第二个方法来练习使用方法。这一次,我们希望 的实例采用另一个实例
of 和 return (如果第二个可以完全适合)
within (第一个);否则,它应返回 .
也就是说,一旦我们定义了方法,我们希望能够编写
程序如图 5-14 所示。Rectangle
Rectangle
Rectangle
true
Rectangle
self
Rectangle
false
can_hold
预期输出将如下所示,因为 的两个维度都小于 的维度,但比 的维度宽 :rect2
rect1
rect3
rect1
Can rect1 hold rect2? true
Can rect1 hold rect3? false
我们知道我们想要定义一个方法,所以它将在 block 中。方法名称将是 ,并且它将接受不可变的借用
作为参数。我们可以看出
参数将通过查看调用该方法的代码来实现: 传入 ,这是对 的不可变借用 ,是 的实例。这是有道理的,因为我们只需要
read (而不是 write,这意味着我们需要一个可变的借款),
并且我们希望保留所有权,以便我们可以在之后再次使用它
调用该方法。的返回值将为
Boolean 的 Boolean 中,实现会检查的 width 和 height 是否大于另一个的 width 和 height ,
分别。让我们将新方法添加到
示例 5-13,如示例 5-15 所示。impl Rectangle
can_hold
Rectangle
rect1.can_hold(&rect2)
&rect2
rect2
Rectangle
rect2
main
rect2
can_hold
can_hold
self
Rectangle
can_hold
impl
当我们使用示例 5-14 中的函数运行这段代码时,我们将得到我们的
期望的输出。方法可以接受我们添加到
signature,这些参数的工作方式与
functions 中的 parameters 进行main
self
关联功能
块中定义的所有函数都称为关联函数,因为它们与以 .我们可以定义
关联的函数(因此
不是方法),因为它们不需要该类型的实例即可使用。
我们已经使用了一个函数,如下所示:函数
在 type 上定义。impl
impl
self
String::from
String
不是方法的关联函数通常用于满足以下条件的构造函数
将返回结构体的新实例。这些通常称为 ,但不是特殊名称,也不内置于语言中。例如,我们
可以选择提供一个名为
一个维度参数,并将其用作宽度和高度,从而使其
更容易创建正方形,而不必指定相同的
value 的 2 倍:new
new
square
Rectangle
文件名: src/main.rs
#[derive(Debug)] struct Rectangle { width: u32, height: u32, } impl Rectangle { fn square(size: u32) -> Self { Self { width: size, height: size, } } } fn main() { let sq = Rectangle::square(3); }
返回类型和函数主体中的关键字是
出现在关键字后面的类型的别名,在本例中为
是。Self
impl
Rectangle
要调用这个关联的函数,我们使用带有 struct name 的语法; 就是一个例子。此函数的命名空间为
struct:该语法用于关联的函数和
由模块创建的命名空间。我们将在 Chapter 中讨论模块
7.::
let sq = Rectangle::square(3);
::
多个 impl
块
每个结构体都可以有多个块。例如,Listing
5-15 相当于示例 5-16 中所示的代码,它的每个方法都在
它自己的块。impl
impl
没有理由在这里将这些方法分成多个块,
但这是有效的语法。我们将看到一个多个块
在第 10 章中很有用,我们在这里讨论泛型类型和 trait。impl
impl
总结
结构允许您创建对您的域有意义的自定义类型。由
使用结构体,您可以保持关联的数据片段彼此连接
并为每个部分命名以使您的代码清晰。在块中,您可以定义
函数,而 methods 是一种
关联的函数,该函数允许您指定
structs 有。impl
但是结构并不是创建自定义类型的唯一方法:让我们转向 Rust 的 enum 功能将另一个工具添加到你的工具箱中。
本文档由官方文档翻译而来,如有差异请以官方英文文档(https://doc.rust-lang.org/)为准