刚开始写 MoonBit 时,有一个疑问:为什么下面的代码可以直接使用 println 和 Json?
println("Hello, MoonBit!")
let data : Json = { "name": "MoonBit" }
经过我一番研究,发现 println 和 Json 的基础定义来自 MoonBit 标准库里的 moonbitlang/core/builtin。
它是最基础的一层标准库包,提供基础类型和常用基础能力。
moonbitlang/core/prelude 是一个普通包。
MoonBit 默认让它在普通程序中可用。
它会导出 builtin 里的常用名称,所以普通代码可以直接使用它们。
后文的 builtin 和 prelude,说的就是这两个包。
可以把这条链路理解成:
builtin 提供基础能力
↓
prelude 用 pub using 导出常用名称
↓
普通 MoonBit 文件默认可以直接使用这些名称
prelude 为什么特殊?
prelude 是一个标准库包,不是 MoonBit 语法。
它的特殊之处在于:编译器会将它带入普通源文件的可见范围。
因此,println 的定义在 builtin 中,但 prelude 导出了这个名字。
Json 也一样。
builtin 提供该类型,prelude 再将它导出。
写普通代码时,不需要为这两个名称显式写 using。
这里的关键是 “自动可见” 这条编译器规则,而不是 prelude 本身变成了语法。
其他标准库名称能否直接使用,要看它是否由 prelude 导出。
还有一类 “直接可用”:语言和内建能力
并非所有不需要导入的内容都来自 prelude。
还有一些内容属于 MoonBit 语言本身,或属于与编译器和运行时紧密配合的基础内建能力。
let value : Int? = Some(42)
let result : Result[Int, String] = Ok(42)
match result {
Ok(number) => println(number)
Err(message) => println(message)
}
其中:
let、fn、match、if、for等是语言语法。Int、String、Bool、Unit、Option、Result等是基础内建类型。Some、None、Ok、Err分别是Option和Result的构造器。?是Option的类型缩写。
例如 Int? 表示一个可能存在、也可能不存在的 Int。
可以这样记:
语言负责让 MoonBit 理解代码的写法和基础数据。
builtin提供基础能力。
prelude把最常用的名称带到普通代码的可见范围中。
当前不需要导入即可使用的 prelude 名称
下面是当前 prelude 公开且未废弃的名称。
它们可以直接写在普通 MoonBit 代码中。
函数和常量
abort、assert_true、assert_false、compare、debug_assertfail、ignore、hash、inspect、panic、physical_equal、printlndebug、debug_inspect、repr、json_inspectassert_eq、assert_not_eqnull
类型和关联构造器
Json(...):把值转换成Json的关联构造器,随Json类型一起可用。Buffer、Set、BigIntArgsLoc、Array、ArrayView、MutArrayView、UninitializedArrayFailure、Hasher、Iter、Iter2Json、Map、InspectError、SnapshotError、SourceLoc、StringBuilderRepr、Regex、Ref、Lazy
可在类型声明中直接使用的接口名
Eq、Compare、Hash、Logger、Show、ToJson、DefaultAdd、Sub、Mul、Div、Mod、Neg、Shl、Shr、BitAnd、BitOr、BitXOrDebug、FromJson
这份名单以当前 moonbitlang/core 仓库的 prelude/prelude.mbt 为准。
标准库仍在演进,后续版本可能调整默认导出的范围。
什么时候仍然需要显式引入?
当需要的名称不在 prelude 中时,就按对应包的使用方式引入。
例如,某个集合、随机数或命令行相关能力没有出现在上面的默认名称清单中,就不能因为它属于标准库而直接使用。
prelude 只导出一小组高频名称,不会覆盖所有标准库能力。
遇到 “为什么这个标准库名称不能直接用” 的问题时,先检查它是否由 prelude 导出,通常就能找到答案。
