Skip to content

03 Methods

方法是与类型相关联的函数, 可以通过实例调用, 也可以通过类型调用(如果是静态方法). 在 YIAN 中, 任何类型都可以定义方法. 方法的定义使用 impl 块, 语法为:

impl<type_parameters> <type> {
    <method_definition1>
    <method_definition2>
    ...
    <method_definitionN>
}

或者

impl<type_parameters> <trait> for <type> {
    <method_definition1>
    <method_definition2>
    ...
    <method_definitionN>
}
  • <type_parameters>: 可选的类型参数列表, 用于定义泛型 impl 块, 泛型 impl 块可以为一个满足特定条件的类型族(而不是一个单一的类型)实现方法, 详见泛型章节
  • <type>: 方法所属的类型
  • <trait>: 方法所属的 trait, 只有在为 trait 实现方法时才需要指定
  • <method_definition>: 方法的定义, 格式与函数定义相同, 包含方法体, 用花括号 { ... } 包围
  • 方法前面可以有访问修饰符以及 static 关键字
  • 使用 impl <type> { ... } 定义的方法称为 inherent method, 使用 impl <trait> for <type> { ... } 定义的方法称为 trait method

Inherent Method

Inherent method 是直接定义在类型上的方法, 实例:

现有自定义 struct Point:

struct Point {
    f32 x
    f32 y
}

下面为 Point 定义两个方法, 一个是实例方法 distance_from_origin, 另一个是静态方法 new:

impl Point {
    // 实例方法, 计算点到原点的距离
    pub f32 distance_from_origin() {
        return (self.x * self.x + self.y * self.y).sqrt()
    }

    // 静态方法, 创建一个新的 Point 实例
    pub static Point new(f32 x, f32 y) {
        return Point(x, y)
    }
}
  • distance_from_origin 是一个实例方法, 通过 self 参数访问调用该方法的实例的字段, 可以通过 point.distance_from_origin() 来调用, 其中 point 是一个 Point 类型的实例
  • new 是一个静态方法, 没有 self 参数, 只能通过 Point.new(x, y) 来调用.

也可以为内置类型定义 inherent method:

impl f32 {
    // 静态方法, 将角度转换为弧度
    pub static f32 from_degrees(f32 degrees) {
        return degrees * 3.141592653589793 / 180.0
    }

    // 实例方法, 计算一个数的根号
    pub f32 sqrt() {
        // 这里使用牛顿迭代法来计算平方根
        f32 guess = self / 2.0
        loop {
            f32 next_guess = (guess + self / guess) / 2.0
            if (next_guess - guess).abs() < 1e-6 {
                break
            }
            guess = next_guess
        }
        return guess
    }
}
  • from_degrees 是一个静态方法, 用于将角度转换为弧度, 可以通过 f32.from_degrees(degrees) 来调用
  • sqrt 是一个实例方法, 用于计算一个 f32 数的平方根, 可以通过 value.sqrt() 来调用, 其中 value 是一个 f32 类型的实例

Trait Method

Trait method 的定义方式和调用方式和 inherent method 完全一致, 唯一的区别是 trait method 的签名必须与 trait 中声明的方法签名完全匹配, 包括方法名, 参数列表, 返回类型以及访问修饰符. 例如, 假设有一个 trait Drawable:

trait Drawable {
    pub draw() {
        // 默认实现, 可以被覆盖
    }
}

下面为 Point 实现 Drawable trait:

impl Drawable for Point {
    pub draw() {
        // 在这里实现绘制 Point 的逻辑, 例如输出坐标
    }
}
  • drawDrawable trait 中声明的方法, 在 impl Drawable for Point 块中为 Point 实现了这个方法