Mojo struct 结构体与生命周期
本篇覆盖:struct 定义、@fieldwise_init、生命周期方法(构造/拷贝)、运算符重载。struct 是 Mojo 组织数据的基本方式,也是它与 Python 分道扬镳的第一站。
一、struct:静态版的 class
Mojo 用 struct 组织自定义类型,概念上对应 Python 的 class,但有一个根本区别:struct 完全静态绑定——字段、方法在编译期就确定,没有运行时动态派发,没有猴子补丁。
mojo
@fieldwise_init
struct MyPair(Copyable):
var first: Int
var second: Int
def dump(self):
print(self.first, self.second)
def main():
var mine = MyPair(2, 4)
mine.dump() # 2 4三个要点:
- 字段用
var声明(和局部变量一样) - 括号里的
Copyable是 trait(下一篇细讲)——声明这个类型支持拷贝 @fieldwise_init自动生成字段级构造函数,不用手写__init__
二、手写生命周期方法
当初始化逻辑比「逐字段赋值」复杂时,需要手写生命周期方法:
mojo
struct MyPair(Copyable):
var first: Int
var second: Int
# 构造函数:注意 out self 约定
def __init__(out self, first: Int, second: Int):
self.first = first
self.second = second
# 拷贝构造:从已有实例创建新实例
def __init__(out self, *, copy: Self):
self.first = copy.first
self.second = copy.second
def dump(self):
print(self.first, self.second)注意 out self:构造函数开始时 self 尚未初始化,函数必须完成初始化后才能返回。这是 Mojo 内存安全的基石之一——不可能拿到「半初始化」的对象。
日常开发中,绝大多数 struct 用 @fieldwise_init + trait 自动合成就够了:
mojo
@fieldwise_init
struct Vec3(Movable, Copyable):
var x: Float64
var y: Float64
var z: Float64三、运算符重载:dunder 方法
和 Python 一致的 dunder 风格:
mojo
@fieldwise_init
struct Vec2(Copyable, Stringable):
var x: Float64
var y: Float64
def __add__(self, rhs: Vec2) -> Vec2:
return Vec2(self.x + rhs.x, self.y + rhs.y)
def __mul__(self, k: Float64) -> Vec2:
return Vec2(self.x * k, self.y * k)
def __str__(self) -> String:
return t"({self.x}, {self.y})"
def main():
var a = Vec2(1.0, 2.0)
var b = Vec2(3.0, 4.0)
print(a + b) # (4.0, 6.0)
print(a * 2.0) # (2.0, 4.0)Stringable trait 要求实现 __str__——实现后 print() 直接可用。这是 trait 系统的第一次亮相:能力靠声明 trait + 实现 dunder 获得,而不是继承。
四、struct vs Python class 对比
| 特性 | Python class | Mojo struct |
|---|---|---|
| 方法绑定 | 运行时动态 | 编译期静态 |
| 字段增删 | 运行时可变 | 编译期锁定 |
| 继承 | 支持多继承 | 用 trait 组合替代 |
| 构造 | __init__(self) | __init__(out self) + @fieldwise_init |
| 性能 | 有解释器开销 | 零成本抽象 |
官方路线图提到未来会支持 Python 风格的动态 class,用于上层胶水代码——Mojo 的思路是静态 struct 管性能路径,未来动态 class 管灵活场景。
五、嵌套与组合
struct 可以包含其他 struct:
mojo
@fieldwise_init
struct Line(Copyable):
var start: Vec2
var end: Vec2
def length(self) -> Float64:
var dx = self.end.x - self.start.x
var dy = self.end.y - self.start.y
return (dx * dx + dy * dy) ** 0.5注意:struct 不能直接包含自身(无限大小)。链表、树这类自引用结构需要用指针(UnsafePointer / Pointer),属于进阶话题。
六、方法中的 self 约定速查
| 形式 | 含义 |
|---|---|
def method(self, ...) | 只读访问(默认不可变引用) |
def method(mut self, ...) | 需要修改字段时 |
def __init__(out self, ...) | 构造:self 待初始化 |
@staticmethod | 静态方法,无 self |
七、小结
- struct = 编译期静态绑定的自定义类型,零成本抽象的载体
- 首选
@fieldwise_init自动生成构造,特殊逻辑才手写__init__(out self, ...) - 能力通过「实现 trait + dunder 方法」组合获得:
Copyable、Movable、Stringable…… - 运算符重载与 Python 同构,迁移心智成本低
下一篇:trait 特征系统。