首页/MoonBit/为什么MoonBit的println和Json可以直接用?

刚开始写 MoonBit 时,有一个疑问:为什么下面的代码可以直接使用 printlnJson

println("Hello, MoonBit!")

let data : Json = { "name": "MoonBit" }

经过我一番研究,发现 printlnJson 的基础定义来自 MoonBit 标准库里的 moonbitlang/core/builtin

它是最基础的一层标准库包,提供基础类型和常用基础能力。

moonbitlang/core/prelude 是一个普通包。

MoonBit 默认让它在普通程序中可用。

它会导出 builtin 里的常用名称,所以普通代码可以直接使用它们。

后文的 builtinprelude,说的就是这两个包。

可以把这条链路理解成:

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)
}

其中:

  • letfnmatchiffor 等是语言语法。
  • IntStringBoolUnitOptionResult 等是基础内建类型。
  • SomeNoneOkErr 分别是 OptionResult 的构造器。
  • ?Option 的类型缩写。

例如 Int? 表示一个可能存在、也可能不存在的 Int

可以这样记:

语言负责让 MoonBit 理解代码的写法和基础数据。

builtin 提供基础能力。

prelude 把最常用的名称带到普通代码的可见范围中。

当前不需要导入即可使用的 prelude 名称

下面是当前 prelude 公开且未废弃的名称。

它们可以直接写在普通 MoonBit 代码中。

函数和常量

  • abortassert_trueassert_falsecomparedebug_assert
  • failignorehashinspectpanicphysical_equalprintln
  • debugdebug_inspectreprjson_inspect
  • assert_eqassert_not_eq
  • null

类型和关联构造器

  • Json(...):把值转换成 Json 的关联构造器,随 Json 类型一起可用。
  • BufferSetBigInt
  • ArgsLocArrayArrayViewMutArrayViewUninitializedArray
  • FailureHasherIterIter2
  • JsonMapInspectErrorSnapshotErrorSourceLocStringBuilder
  • ReprRegexRefLazy

可在类型声明中直接使用的接口名

  • EqCompareHashLoggerShowToJsonDefault
  • AddSubMulDivModNegShlShrBitAndBitOrBitXOr
  • DebugFromJson

这份名单以当前 moonbitlang/core 仓库的 prelude/prelude.mbt 为准。

标准库仍在演进,后续版本可能调整默认导出的范围。

什么时候仍然需要显式引入?

当需要的名称不在 prelude 中时,就按对应包的使用方式引入。

例如,某个集合、随机数或命令行相关能力没有出现在上面的默认名称清单中,就不能因为它属于标准库而直接使用。

prelude 只导出一小组高频名称,不会覆盖所有标准库能力。

遇到 “为什么这个标准库名称不能直接用” 的问题时,先检查它是否由 prelude 导出,通常就能找到答案。