Mojo 基础知识参考字典

要点

Mojo 的基础条目按用途分成四组:声明与结构、函数与参数、常用类型与集合、内存与互操作。每个条目给签名、一句话语义、最小示例和坑,示例自包含,粘进 25.4 时点的 pixi run mojo repl 或文件里就能跑。字典是查的不是读的——”为什么这样设计”的叙事版在《Mojo 语法要点》,本文只做条目式速查,文末速查表是全量索引。Mojo 处于快速演进期,版本敏感的写法在条目里单独标注,示例以 25.4(2025-06-18 发布)为准。

声明与结构

组内共性:Mojo 有两个世界——def 代表的动态世界、fn/struct/alias 代表的编译期世界。这组条目决定你的代码活在哪个世界里,混用时的大部分编译报错都源于世界的错配。

def 与 fn

def parse(raw):                     # 动态模式:参数可不标类型
    parts = raw.split(",")          # 变量可隐式声明
    return parts

fn circle_area(r: Float64) -> Float64:   # 严格模式:类型与返回值必标
    return 3.14159 * r * r

脚本与胶水代码用 def,性能关键路径用 fn;同一文件可以混用,fn 可以被 def 调用。

⚠️ 坑:同一个”改参数”的动作在两边行为不同——def 的参数是可变副本(改了不影响调用者),fn 的参数默认只读借用(赋值直接编译报错)。从 Python 拷来的函数在 fn 里报错,十有八九是这个。

var

fn f() -> Int:
    var x = 10          # fn 里必须 var 显式声明
    x += 1
    return x

var 声明可变局部变量,是 fn 世界里变量出生的唯一方式。

⚠️ 坑:24.x 之前旧代码里的 let 关键字已经删除,见到 let 一律当 var 读;def 里不写 var 也能隐式声明,fn 里不行——”undeclared variable” 报错先补 var。

struct 与 @fieldwise_init

@fieldwise_init              # 自动生成逐字段构造器
struct Point:
    var x: Float64           # 字段类型必标
    var y: Float64

fn main():
    var p = Point(x=1.0, y=2.0)
    print(p.x + p.y)         # 3.0

静态类型载体:字段与方法编译期确定,内存布局与 C 结构体同量级。

⚠️ 坑:没有继承,”找个父类”这条路不存在(复用走 trait);旧教程的 @value 已弃用,对应关系是换算成 @fieldwise_init;不写 @fieldwise_init 也不手写 __init__ 时,Point(...) 这种构造调用不存在。

trait 遵循

struct Pair(Copyable, Movable):   # 遵循声明写在结构体名后的括号里
    var k: Int
    var v: Float64

trait 是 Mojo 的”接口”:约束泛型参数、给类型贴能力标签,常见内置 trait 有 AnyType、Copyable、Movable、Stringable、Intable、Equatable、Hashable 等。

⚠️ 坑:需要拷贝/移动某 struct 而编译器报 trait 错误时,多数是括号里漏声明或字段不可拷贝;实现 trait 的方法名在 25.x 间有过改名(部分 dunder 改为普通名),具体拼写以官方文档为准。

alias

alias N = 128                 # 编译期常量
alias WIDTH = 4

var v = SIMD[DType.float64, WIDTH](0)   # 能进方括号参数

编译期求值的命名常量,是 struct/函数方括号参数世界的”货币”。

⚠️ 坑:与 var 的区别不是”不可变”,是”存在于哪个世界”——var 的值进不了编译期参数位;alias 只能装编译期可求值的表达式,塞运行时才有的东西直接报错。官方仓库里 alias 改名的讨论已挂多年,语义稳定、拼写可能变,以官方文档为准。

函数与参数

组内共性:Mojo 的函数签名即文档——参数怎么进来、会不会改、错误怎么走,全部写在签名里,读签名就能预判行为。

参数约定 read / mut / owned / out

from collections import List

fn fill(mut buf: List[Float64], v: Float64):   # mut:改动写回调用者
    for i in range(len(buf)):
        buf[i] = v

fn main():
    var xs = List[Float64](0.0, 0.0)
    fill(xs, 9.9)
    print(xs)                 # [9.9, 9.9]

默认(read)只读借用零拷贝;mut 可变借用;owned 接管所有权;out 用于构造器与结果参数(__init__(out self))。

⚠️ 坑:fn 参数赋值报错不是语言 bug,是默认 read 在工作——想改就标 mut,想消耗才用 owned,别为了消报错乱标;读 24.x 老教程要换算:borrowed 即现在的默认 read,inout 即 mut。

方括号编译期参数

fn zeros[W: Int]() -> SIMD[DType.float64, W]:
    return SIMD[DType.float64, W](0)

fn main():
    var v = zeros[4]()        # 方括号实参编译期定型
    print(v.reduce_add())     # 0.0

方括号是编译期参数、圆括号是运行时参数:一个函数两套维度,宽度、形状、类型这类”结构性信息”走方括号。

⚠️ 坑:方括号实参必须是编译期已知(字面量或 alias),报错出现 “must be known at compile time” 时,把运行时算出来的值改成 alias 才是正解,绕不是办法。

@parameter if

alias WIDTH = 8

fn pick() -> Int:
    @parameter if WIDTH >= 8:
        return WIDTH      # 编译期分支:不成立的分支整体消失
    else:
        return 1

编译期条件分支,配合 alias 实现同一份代码的多条编译路径。

⚠️ 坑:条件必须是编译期值,拿运行时变量当条件直接报错——那是普通 if 的活。

raise 与 try / except

fn checked_div(a: Float64, b: Float64) raises -> Float64:
    if b == 0.0:
        raise Error("division by zero")
    return a / b

def main():
    try:
        checked_div(1.0, 0.0)
    except e:
        print("failed:", e)

错误处理是 Python 风格的 raise/try/except,错误对象以 Error 为基类。

⚠️ 坑:fn 会抛错就必须在签名里写 raises,漏写是高频编译错误;def 可以隐式抛错不用声明。自定义错误类型的继承写法与机制仍在演进,以官方文档为准。

常用类型与集合

组内共性:名字与 Python 同名的类型,语义都是”编译期固定类型”的版本——类型参数在方括号里,元素类型不可变着玩。

Int

fn main():
    var a: Int = 42
    var f = 7 / 2             # Int / Int 得 Float64
    var g = 7 // 2            # 整除用 //
    print(f, g)               # 3.5 3

固定宽度的带符号整数(常见实现为 64 位),不是 Python 的任意精度 int。

⚠️ 坑:从 Python 迁移的算法里,依赖”大数自动升位”的代码要重写;除法语义与 Python 有差异——/ 得浮点、// 才是整除,混着写会产生难查的精度问题。

Float64 与 SIMD

fn main():
    var x: Float64 = 3.14                    # Float64 = SIMD[DType.float64, 1]
    var v = SIMD[DType.float32, 8](0)        # 8 通道全零
    var w = v * 2.0 + 1.0                    # 逐通道算术
    print(w.reduce_max())                    # 归约取最大通道

浮点标量是宽度 1 的 SIMD 别名,向量化就是把宽度参数从 1 调大,逐通道运算与归约(reduce_add / reduce_max / reduce_min)是高频操作。

⚠️ 坑:不同宽度、不同精度的 SIMD 混算需要显式转换(cast 一族方法),隐式混合直接报错;Int 不在 SIMD 体系里,”标量都是 SIMD”只对浮点成立。

String

fn main():
    var n = str(25)          # 内置 str:数字转字符串
    print("Mojo", n, 25.4)   # print 收多参数,空格分隔

UTF-8 字符串类型,日常拼装与打印够用。

⚠️ 坑:字符串类型体系在 25.x 持续重构(String 与 Span/StringSlice 一族的关系、方法集都有变动),切片与方法名以官方文档为准,别把 Python str 的全部方法集当成默认存在。

List

from collections import List

fn main():
    var xs = List[Float64](1.0, 2.0, 3.0)
    xs.append(4.0)
    print(len(xs))           # 4

动态数组,元素类型编译期固定,append/len/下标读写覆盖日常。

⚠️ 坑:25.x 起 List/Dict 属于 collections 模块,忘了 from collections import List 是报错头名(更早版本是内置名);Python 心智的 xs + [5.0] 拼接写法不存在,用 append。

Dict

from collections import Dict

fn main():
    var d = Dict[String, Int]()
    d["a"] = 1
    print(len(d))            # 1

哈希表,键值类型编译期固定。

⚠️ 坑:缺键的 [] 访问会抛错,Python dict.get 的兜底习惯不能直接搬(兜底写法以官方文档为准);键类型要满足可哈希约束(KeyElement 一族 trait),自定义 struct 当键时先确认遵循。

内存与互操作

组内共性:这组条目是 Mojo 区别于 Python 的”系统层”,收益是贴近硬件的性能,代价是安全检查交还给你自己。

UnsafePointer

fn main():
    var p = UnsafePointer[Float64].alloc(4)   # 堆上 4 个 Float64
    p.store(0, 1.25)                          # 写单个元素
    print(p.load(0))                          # 读单个元素

裸指针:手动分配(alloc)、按偏移读写(load/store)、向量化批量读写走 load/store 的宽度参数形式。

⚠️ 坑:名字里的 Unsafe 是认真的——无越界检查、无生命周期管理;持有它的 struct 默认拷贝是浅拷贝,两份指针指向同一块内存,转移还是共享必须显式想清楚。不确定自己为什么需要它时,先用 List。

Python 互操作

from python import Python

def main():
    np = Python.import_module("numpy")
    a = np.arange(5)
    print(a.sum())     # 计算走 NumPy 自己的实现

直接 import 整个 Python 生态,拿到的是 PythonObject,方法属性原样可用。

⚠️ 坑:互操作不是加速器——计算性能取决于被调的 Python 库,加速靠把热点循环改写成 Mojo 原生;在 fn 里操作 Python 对象要持有 GIL(Python.with_gil 一族,具体以官方文档为准);本机需有可用的 Python 环境。

mojo CLI 与 pixi

pixi init hello-mojo && cd hello-mojo    # 项目化安装,不污染全局
pixi add mojo                            # 从 modular-community 渠道装 Mojo
pixi run mojo --version                  # 所有 mojo 命令走 pixi run 前缀
pixi run mojo run hello.mojo             # 运行单文件
pixi run mojo build hello.mojo           # 编译成独立可执行文件
pixi run mojo repl                       # 交互式环境

三条命令覆盖”跑、编、试”:run 执行脚本,build 出二进制,repl 即写即试。

⚠️ 坑:忘了 pixi run 前缀,命中的可能是系统环境甚至没有 mojo;mojo run 的选项要写在文件路径之前;25.x 各版本间 CLI 与标准库 API 都有破坏性变更,升级后先看 changelog 再跑旧代码。

速查表

条目 一句话用途 有什么坑
def / fn 动态模式与严格模式分工 def 参数是可变副本,fn 参数默认只读(赋值报错)
var 声明可变局部变量 let 已删除;fn 里必须 var,def 可隐式
struct / @fieldwise_init 静态类型载体与逐字段构造器 无继承;@value 已弃用;没构造器不能 Point(…)
trait 能力标签与泛型约束,替代继承 括号漏声明报 trait 错;方法名有版本间改名
alias 编译期常量,方括号参数的货币 只装编译期值;命名演进以官方文档为准
read / mut / owned / out 参数所有权约定 默认 read 改参报错;旧名 borrowed/inout 要换算
方括号参数 [W: Int] 编译期参数化函数与 struct 实参必须编译期已知,运行时值进不来
@parameter if 编译期分支 条件必须是编译期值
raise / try / except Python 风格错误处理 fn 抛错必须签名写 raises
Int 固定宽度整数 非任意精度;/ 得浮点,// 才整除
Float64 / SIMD 浮点标量即宽度 1 向量 混宽度要显式 cast;Int 不在 SIMD 体系
String UTF-8 字符串 类型体系持续重构,方法名以官方文档为准
List 动态数组 记得 from collections import;拼接用 append
Dict 哈希表 缺键抛错,get 兜底习惯不能搬
UnsafePointer 裸指针 alloc/load/store 无越界无生命周期;struct 浅拷贝共享指针
python 模块 import 任意 Python 生态 不是加速器;fn 里要 GIL;需本机 Python
pixi + mojo CLI run/build/repl 三件套 忘 pixi run 前缀命中错环境;升级先看 changelog

下一步

条目查完,两个方向:要看这些语法在真实性能场景里怎么组合,读《用 Mojo 加速矩阵乘法》——UnsafePointer、SIMD、parallelize 全部上场;要规划学什么、按什么顺序学,读开山篇的观察结论与本系列的收尾篇《Mojo 学习路线》。与 Python 侧同名概念的系统对照(内置函数那一层),站内已有《Python 内置函数详解》。

版本核实(以官方文档为准):条目以 25.4(2025-06-18 发布)时点的官方文档为基准——参数约定 read/mut/owned/out(25.1 起定名)、@fieldwise_init(@value 弃用)、let 已删除、collections 模块的 List/Dict、SIMD 归约方法、UnsafePointer 的 alloc/load/store、python 模块互操作与 pixi 安装路线均为已发布事实;String 类型体系、trait 方法命名、自定义错误机制在 25.x 内持续演进,具体拼写以 docs.modular.com 当前文档为准。本文未引用 25.5 及以后版本的特性。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇