20260608 MoonBit v0.10.0
对应 moonc 版本:v0.10.0+84519ca0a
需要说明的是,本次月报介绍的是 MoonBit 0.10 版本。它可以看作是 1.0 正式版发布前的一次关键更新,我们正在围绕语言稳定性、工具链完善和生态体验做最后阶段的打磨。按照目前规划,MoonBit 预计将在今年第三季度发布 1.0 正式版,后续进展也会通过月报持续同步给大家。
语言更新
-
trait和impl语法现在需要添加fn关键字:trait I { fn f(Self) -> Unit //^^ } impl I for Int with fn f(_) {} // ^^这一改动主要是为了方便为
trait添加多态方法支持。现有代码只需要运行moon fmt即可自动完成迁移。目前旧的、没有fn的语法依然支持。下个版本中旧语法将开始产生警告,并会在未来被移除。.mbtp文件中的impl现在也需要强制添加fn关键字。 -
多态
trait方法支持trait中的方法现在可以有自己的类型参数了:trait Logger { fn[X : Show] write_object(Self, X) -> Unit } impl Logger for StringBuilder with fn write_object(self, x) { self.write_string(x.to_string()) }在实现一个多态的
trait方法时,方法自身的类型参数无需显式标注。如果想要显式标注,需要将方法自身的类型参数标注 在fn关键字后,而impl自身的类型参数依然标注在impl关键字后:trait Poly { fn[X] f(Self, X) -> Unit } impl[A] Poly for Array[A] with fn[X] f(self, x : X) { // ^^^ impl 的类型参数 ^^^ 方法的类型参数 ... } -
for .. in循环支持状态变量的默认更新:for i in 0..<10; p1 = 1, p2 = 0; p1 = p1 + p2, p2 = p1 { // ^^^^^^^^^^^^^^^^^^^^^ // 本次新增。语义和 `for` 循环的默认更新一致。 // 没有显式调用带参数的 `continue` 时, // 每次循环结束后会根据这里的声明来更新循环变量的值 println("fib#\{i + 1} = \{p1}") } -
List comprehension 支持
for .. in的额外循环变量:let fibs = [ for _ in 0..<10 p1 = 1, p2 = 0 p1 = p1 + p2, p2 = p1 => { p1 } ] -
使用 list comprehension 构建
Iter以外的类型时,list comprehension 内部可以包含副作用。例如raise和async。 -
字符串插值改进
-
之前的字符串插值会编译成字符串拼接,现在改为编译成高效的
StringBuilder写入。例如let r = "a\{b}c":// 之前的编译结果 let r = "a" + b.to_string() + "c" // 现在的编译结果 let r = { let builder = StringBuilder(size_hint=2) builder.write_string("a") builder.write(b) builder.write_string("c") builder.to_string() } -
字符串插值
\{...}内不再限制{、}、"的使用,字符串插值允许嵌套。let xs = ["cd", "ef"] let r1 = "ab\{xs.join(";")}" assert_eq(r1, "abcd;ef") -
字符串插值
\{...}内支持嵌套匿名函数,这种情况会被特殊处理:let r = "a\{builder => builder.f()}" // 相当于 let r = { let builder = StringBuilder() builder.write_string("a") (builder => builder.f())(builder) builder.to_string() }
-
-
新增模板写入语法
lhs <+ rhs我们发现在 web 后端开发时,经常出现用缓冲区拼凑字符串的模式:
fn render( style : String, li_class : String, items : Array[String], ) -> String { let buf = StringBuilder() // <ul prop=foo> buf..write_string("<ul prop=foo>") // <li class="{li_style}">{item}</li> for item in items { buf..write_string("<li class=\"") ..write(li_class) ..write_string("\">") ..write(item) .write_string("</li>") } // </ul> buf.write("</ul>") buf.to_string() }手动调用
StringBuilder::write_string和StringBuilder::write非常繁琐。虽然这一场景也可以使用 HTML DSL 或者 模板引擎代替,但它们会引入额外的内存分配和字符串替换开销。模板写入语法提供了一种更轻量、易读、零额外开销的解决方案,下面是使用新特性的等价代码:fn render( style : String, li_class : String, items : Array[String], ) -> String { let buf = StringBuilder() buf <+ "<ul prop=foo>" for item in items { buf <+ $|<li class="\{li_class}">\{item}</li> } buf <+ "</ul>" buf.to_string() }对于
buf <+ "a\{b}",它会直接被分解为buf..write_string("a")..write(b)。操作符
<+右侧允许下面的表达式:-
字符串
"abc\{x}" -
多行字符串
#| multiline string... -
多行字符串插值
$| multiline string with \{x} -
map 字面量
{"k1": v1, "k2": v2}
操作符
<+左侧表达式的类型不要求是StringBuilder,它可以是任意实现了下面方法的类型T:-
T::write_string(T, String) -
T::write(T, X) -
(可选)如果要支持写入 map 字面量,需要实现
T::write_object_begin(T)、T::write_object_field(T, String, X)和T::write_object_end(T)
字符串插值
\{...}的语法规则和普通字符串插值一致。 -
-
新增条件模板写入语法
lhs <? rhs在模板写入语法的基础上,写入可以带前置条件。这在 debug logging 等场景非常有用:我们希望程序在调试模式才输出 debug 信息,而正常模式下不会付出 logging 开销。下面的例子中,
logger类型为Option[T],调试模式下logger的值是Some(...),正常模式为None。logger <? "[tag] message \{x}..." // 等价于 if logger is Some(x) { x <+ "[tag] message \{x}..." } -
移除旧版 struct constructor 语法
此前已经废弃的
fn new(..)自定义构造器写法不再被支持,新的构造器写法统一为fn Type::Type(..)。 -
弃用
try?语法编译器检查时会给出迁移建议。
-
添加实验性内置
V128类型目前它在 wasm/wasm-gc 后端会编译成
v128类型;在生成 C 代码的 native 后端中,会在支持 NEON 的 Arm 架构上编译为uint8x16_t,在支持 SSE2 的 x86 架构上编译为__m128i。其他情况下会使用两个uint64进行模拟。以上内容不作 ABI 承诺,后续会通过标准库提供高效的V128操作。
工具链更新
-
新的 MoonBit native 后端已经发布,并可通过
MOONBIT_NEW_NATIVE=1环境变量试用,仅支持 macOS Apple Silicon;Linux 和 Windows 的支持将会逐步推出。 -
新增
moon test --profile和moon run --profile功能。macOS 上会调用xctrace对 native 程序进行 profile,Linux 平台支持也已经完成。 -
新增
--diagnostics-limit来限制 error 和 warning 数量,并减少失败时直接打印底层moonc命令带来的噪音。 -
Wasm 后端的
println已替换为基于 WASI 的实现。 -
实验性
moon runwasm命令和 SKILL 市场使用
moon runwasm Yoorkin/cowsay -- hello可以直接运行在 mooncakes.io 发布的、支持 Wasm target 的包。mooncakes.io 会自动为支持 Wasm 编译目标的包构建经过 wasm-opt 优化的*.wasm,并将同目录的SKILL.md放在 mooncakes.io/skills 页面展示:

-
默认使用
moon.mod代替原moon.mod.jsonmoon.mod已支持supported_targets、preferred_target、readme、license、keywords、repository、description等顶层字段;moon fmt默认启用从moon.mod.json到moon.mod的迁移,遇到问题时可通过NEW_MOON_MOD=0关闭。 -
moon add path/to/mod的行为做了调整:再次添加已有依赖时只给出警告,不再隐式更新版本;需要更新时使用moon add --upgrade path/to/mod。 -
Native LSP 已成为默认 LSP,并且新增
moon.mod和moon.pkg的 LSP 支持。 -
新增实验性的
moon cram test命令,用于 MoonBit CLI 应用测试。该命令会首先使用 native 后端构建项目中的 CLI 程序,然后将它们放进PATH变量,之后运行 cram test。基本的使用例子请见 moonbit-community/cram_test_poc。 -
新增实验性的
moon run --profile和moon test --profile工具,目前仅支持 macOS 和 Linux 平台下的 native 后端,会分别使用xctrace和perf进行 profile,并对结果中的符号进行 demangle。
标准库更新
-
moonbitlang/async目前最新版本为 0.19.2,自上次 月报(0.19.0)以来的主要更新如下:-
添加了监听文件系统变动的功能。可以通过
@fs.Watcher(..)来监听某个目录下的所有子文件/子文件夹中的变动。目前@fs.Watcher仅提供了wait_any方法,暂不支持汇报具体的变动内容。汇报具体变动内容的功能将在未来添加。更多细节详见@fs.Watcher的文档。 -
添加了
@raw_fd.RawFdStream类型,该类型类似@raw_fd.RawFd,但实现了@io.Reader/@io.Writer。可以用于更方便地操作具有流式语义的 file descriptor。 -
添加了
@async.Mutex类型,可以用于在多个并行任务间进行同步。 -
加入可选的 fd 泄漏检查,可通过
MOONBIT_ASYNC_CHECK_FD_LEAK=1开启。开启后,如果程序忘记释放一些由moonbitlang/async管理的资源(例如文件),程序退出前会abort并提示有泄露问题。
-