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 实现 trait:struct MyType(SomeTrait) 语法,编译器强制检查所有方法都已实现。
泛型参数 [T: SomeTrait]:编译期单态化,为每种具体类型生成专用代码,零虚函数调用开销。
内置 trait:Comparable(排序/比较)、Stringable(打印)、Sized(len())、Movable(移动语义)等。
trait 组合:[T: TraitA & TraitB] 要求 T 同时实现多个 trait,实现精确的能力约束。