weekly 2024-09-18
MoonBit更新
-
type支持将字段访问传递到内部的类型struct UnderlyingType { field1 : Int field2 : Bool } type Newtype UnderlyingType fn main { let newtype = Newtype({ field1: 100, field2: true }) println(newtype.field1) // 100 println(newtype.field2) // true }原先要操作
newtype内的UnderlyingType的字段field1,必须以newtype._.field1形式访问。简化后,对Newtype的字段访问将自动传递到UnderlyingType:可以直接书写newtype.field1访问UnderlyingType内的field1。 -
支持自定义类型通过 derive 实现
ToJson和FromJsontraitderive(ToJson)会自动为类型生成相关实现。输出的json格式符合自动生成的FromJson的要求。struct Record { field1 : Int field2 : Enum } derive(Show, ToJson, FromJson) enum Enum { Constr1(Int, Bool?) Constr2 } derive(Show, ToJson, FromJson) fn main { let record = { field1: 20, field2: Constr1(5, Some(true)) } println(record.to_json().stringify()) // output: {"field1":20,"field2":{"$tag":"Constr1","0":5,"1":true}} let json = record.to_json() try { let record : Record = @json.from_json!(json) println(record) // output: {field1: 20, field2: Constr1(5, Some(true))} } catch { @json.JsonDecodeError(err) => println(err) } } -
卫语句(guard statement)
卫语句有
guard和guard let两种形式,用于保证不变量和消除模式匹配带来的缩进。fn init { guard invariant else { otherwise } continue_part }guard中的invariant是类型为Bool的表达式。当invariant为真时,对continue_part求值并返回结果;当invariant为假时,对otherwise求值并返回求值结果,跳过余下的continue_part。else { otherwise }部分是可选的,省略时,当invariant为假,程序终止。fn init { guard let ok_pattern = expr1 else { fail_pattern1 => expr2 fail_pattern2 => expr3 } continue_part }guard let 与 guard 类似,支持额外的模式匹配。当
expr1可以被ok_pattern匹配时,执行continue_part;否则尝试匹配 else 内的分支。else 部分省略或者没有匹配的分支时程序终止。ok_pattern可以引入新的绑定,它的作用域是整个continue_part。一个例子:fn f(map : Map[String,Int]) -> Int!Error { guard let Some(x) = map["key1"] else { None => fail!("key1 not found") } x + 1 } -
moonfmt调整
对于不在语句的上下文中使用的
if、match、loop、while、for、try表达式,格式化后会自动加上括号。 我们将在下一周调整if、match、loop、while、for、try和中缀表达式的优先级,这是一个破坏性的变更。调整后,前者这些表达式不再能够直接出现在语法上要求是中缀表达式的位置。例如,下面的代码未来都是不合法的:if if cond {a} else {b} {v} else {d} match match expr { ... } { ... } let a = expr1 + expr2 + if a {b} else {c} + expr3 guard if a {b} else {c} else { d }调整后,原先的代码需要额外的括号:
if (if cond {a} else {b}) {v} else {d} match (match expr { ... }) { ... } let a = expr1 + expr2 + (if a {b} else {c}) + expr3 guard (if a {b} else {c}) else { d }我们更建议使用
let x = y对if、match等表达式的中间结果引入新的绑定,来改善代码的可读性,这不会引入额外的开销。例如:// 不建议的用法 match (match expr { ... }) + (if a {b} else {c}) + expr { ... } // 建议的用法 let r1 = match expr { ... } let r2 = if a {b} else {c} match r1 + r2 + expr { ... }除此之外,对于
.land(),lor(),shl(),op_shr等函数,格式化后会自动变为中缀运算符&,|,<<,>>。
IDE更新
- 支持项目全局的符号搜索

- 修复重命名时会把包名覆盖的问题
- 优化插件自动执行 moon check 的逻辑
- 增加关键字和 Bool 字面量的补全
- 适配构建系统的条件编译,同时兼容原来的文件名后缀区分后端的方式(x.wasm.mbt, x.js.mbt)
构建系统更新
-
支持构建图可视化,在
moon check|build|test后传递 --build-graph,完成编译后会在对应的构建目录中生成此次构建图的 .dot 文件 -
moon.pkg.json添加targets字段,用于编写条件编译表达式,条件编译的粒度为文件。条件编译表达式中支持三种逻辑操作符and,or和not,其中or可以省略不写,例如["or", "wasm", "wasm-gc"]可简写为["wasm", "wasm-gc"]。条件表达式中具体的条件分为后端和优化等级。其中后端包括:"wasm","wasm-gc"和"js"。优化等级包括:"debug"和"release"。条件表达式支持嵌套。此外,如果一个文件未出现在"targets"中,默认在所有条件下都会编译。写法样例
{ "targets": { "only_js.mbt": ["js"], "not_js.mbt": ["not", "js"], "only_debug.mbt": ["and", "debug"], "js_and_release.mbt": ["and", "js", "release"], "js_only_test.mbt": ["js"], "complex.mbt": ["or", ["and", "wasm", "release"], ["and", "js", "debug"]] } } -
moon.pkg.json添加pre-build字段用于配置构建的前序命令,其描述的命令会在执行moon check|build|test之前执行。其中pre-build是一个数组,数组中的每个元素是一个对象,对象中包含inputoutputcommand三个字段,input和output可以是字符串或者字符串数组,command是字符串,command中可以使用任意命令行命令,以及$input$output变量,分别代表输入文件、输出文件,如果是数组默认使用空格分割。目前内置了一个特殊命令:embed,用于将文件转换为MoonBit源码,-text参数用于嵌入文本文件,-binary用于嵌入二进制文件,-text为默认值,可省略不写。-name用于指定生成的变量名,默认值为resource。命令的执行目录为当前moon.pkg.json所在目录。
写法样例:
moon.pkg.json
{
"pre-build": [
{
"input": "a.txt",
"output": "a.mbt",
"command": ":embed -i $input -o $output"
}
]
}
如果 a.txt 的内容为
hello,
world
执行 moon build 后,在此 moon.pkg.json所在目录下生成如下 a.mbt 文件
let resource : String =
#|hello,
#|world
#|
-
moon test --target all添加[wasm]等后端后缀,显示效果如下$ moon test --target all Total tests: 0, passed: 0, failed: 0. [wasm] Total tests: 0, passed: 0, failed: 0. [wasm-gc] Total tests: 0, passed: 0, failed: 0. [js]