Chapter 07

特征与泛型

用 trait 定义行为接口,用泛型写出可重用的高性能通用代码

trait 特征:定义行为接口

什么是 trait?

Mojo 的 trait 是一种定义行为契约的机制,与 Rust 的 trait、Swift 的 protocol、Java/C# 的 interface 概念类似。它描述了"一个类型必须支持什么操作",而不关心具体实现细节。通过 trait,你可以写出对多种类型都有效的通用函数,同时保持编译期类型安全。

与 Python 鸭子类型的对比

# Python:鸭子类型
# "只要有 area() 方法就行"
def print_area(shape):
    print(shape.area())  # 运行时才检查

# 如果 shape 没有 area() 方法
# → AttributeError,运行时崩溃
# Mojo:trait(编译期保证)
trait Shape:
    fn area(self) -> Float64: ...

fn print_area[T: Shape](shape: T):
    print(shape.area())  # 编译期保证
# 不满足 Shape → 编译错误

定义和实现 trait

# 定义 trait
trait Shape:
    fn area(self) -> Float64: ...
    fn perimeter(self) -> Float64: ...
    fn name(self) -> String: ...

# 实现 trait(struct 上使用 conforming to)
struct Circle(Shape):
    var radius: Float64

    fn __init__(inout self, r: Float64):
        self.radius = r

    fn area(self) -> Float64:
        return 3.14159 * self.radius ** 2

    fn perimeter(self) -> Float64:
        return 2 * 3.14159 * self.radius

    fn name(self) -> String:
        return "Circle"

struct Rectangle(Shape):
    var width: Float64
    var height: Float64

    fn __init__(inout self, w: Float64, h: Float64):
        self.width = w; self.height = h

    fn area(self) -> Float64:
        return self.width * self.height

    fn perimeter(self) -> Float64:
        return 2 * (self.width + self.height)

    fn name(self) -> String:
        return "Rectangle"

泛型函数

[T: SomeTrait] 泛型参数

泛型函数使用方括号 [T: SomeTrait] 声明类型参数,约束 T 必须实现指定 trait。这是编译期单态化(monomorphization):编译器为每个具体类型 T 生成专门的高效代码,没有运行时虚函数调用开销。

# 泛型函数:接受任何实现了 Shape trait 的类型
fn describe_shape[T: Shape](s: T):
    print(s.name(), "- 面积:", s.area(), "周长:", s.perimeter())

# 多个 trait 约束
fn compare_areas[T: Shape, U: Shape](s1: T, s2: U) -> Bool:
    return s1.area() > s2.area()

fn main():
    var c = Circle(5.0)
    var r = Rectangle(4.0, 6.0)

    describe_shape(c)   # Circle - 面积:78.54 周长:31.42
    describe_shape(r)   # Rectangle - 面积:24.0 周长:20.0

    print(compare_areas(c, r))  # True(圆面积更大)

内置 trait 详解

Comparable
要求实现 __lt__(小于)、__le____eq____ne____gt____ge__。实现后可以用 <> 等运算符比较,以及用于排序算法。
Stringable
要求实现 __str__(self) -> String。实现后可以用 print() 打印,以及用于字符串格式化。
AnyType
所有 Mojo 类型都自动实现的基础 trait,表示"任意类型"。用于写接受任意类型参数的泛型函数时,约束最宽松。
Sized
要求实现 __len__(self) -> Int。实现后可以用内置 len() 函数获取长度,适用于容器类型。
Movable
要求实现 __moveinit__(移动构造函数)。让类型支持高效的所有权转移,避免不必要的拷贝。
Copyable
要求实现 __copyinit__(拷贝构造函数)。让类型支持显式复制,Mojo 中复制是明确的操作,不像 Python 那样隐式。

实现内置 trait

struct Temperature(Comparable, Stringable):
    var celsius: Float64

    fn __init__(inout self, c: Float64):
        self.celsius = c

    fn __str__(self) -> String:
        return String(self.celsius) + "°C"

    fn __lt__(self, other: Temperature) -> Bool:
        return self.celsius < other.celsius

    fn __eq__(self, other: Temperature) -> Bool:
        return self.celsius == other.celsius

    fn __le__(self, other: Temperature) -> Bool:
        return self < other or self == other

    fn __gt__(self, other: Temperature) -> Bool:
        return not (self <= other)

    fn __ge__(self, other: Temperature) -> Bool:
        return not (self < other)

    fn __ne__(self, other: Temperature) -> Bool:
        return not (self == other)

实战:通用排序算法

# 基于 Comparable trait 的泛型插入排序
fn insertion_sort[T: Comparable & Copyable](inout arr: List[T]):
    """泛型插入排序:适用于任何实现了 Comparable 的类型。"""
    let n = len(arr)
    for i in range(1, n):
        var key = arr[i]
        var j = i - 1
        while j >= 0 and arr[j] > key:
            arr[j + 1] = arr[j]
            j -= 1
        arr[j + 1] = key

fn main():
    # 对 Int 数组排序
    var ints = List[Int](5, 2, 8, 1, 9, 3)
    insertion_sort(ints)
    print(ints)  # [1, 2, 3, 5, 8, 9]

    # 对 Float64 数组排序(同一函数!)
    var floats = List[Float64](3.14, 1.41, 2.71)
    insertion_sort(floats)
    print(floats)  # [1.41, 2.71, 3.14]

    # 对 Temperature 排序(自定义类型!)
    var temps = List[Temperature](
        Temperature(37.5), Temperature(20.0), Temperature(100.0)
    )
    insertion_sort(temps)
    for t in temps:
        print(t[])  # 20.0°C, 37.5°C, 100.0°C
本章小结

trait:Mojo 的接口抽象机制,定义类型必须提供的行为,类似 Rust trait / Swift protocol。
struct 实现 traitstruct MyType(SomeTrait) 语法,编译器强制检查所有方法都已实现。
泛型参数 [T: SomeTrait]:编译期单态化,为每种具体类型生成专用代码,零虚函数调用开销。
内置 traitComparable(排序/比较)、Stringable(打印)、Sized(len())、Movable(移动语义)等。
trait 组合[T: TraitA & TraitB] 要求 T 同时实现多个 trait,实现精确的能力约束。