语言更新
1、用于表示错误的 ! 语法被替换为关键字 raise
- 用于表示错误的
!
语法被替换为关键字raise
,具体的对应如下:(..) -> T ! SomeErr
=>(..) -> T raise SomeErr
(..) -> T !
=>(..) -> T raise
(..) -> T ? Error
=>(..) -> T raise?
(这是近期新增的错误多态语法,不了解可以略过)fn f!(..) { .. }
=>fn f(..) raise { .. }
fn!( ..) { .. }
=>fn (..) raise { .. }
上述改动都可以通过格式化代码自动完成迁移
2、定义错误类型的语法 type! T ..
改为 suberror T ..
- 定义错误类型的语法
type! T ..
改为suberror T ..
。这一改动可以通过格式化代码自动完成迁移
3、 f!(..)
/ f?(..)
废弃警告及迁移注意事项
f!(..)
和f?(..)
语法被废弃,继续使用它们会收到编译器的警告。格式化代码能够自动去掉!
完成迁移,但f?(..)
需要手动迁移至try?
。因为对于原先的f?(g!(..))
这种情况,简单改成try? f(g(..))
会改变语义,使g
中的错误也被捕获。在手动迁移f?(..)
时,也需要特别注意这种情况
4、函数类型参数语法更新: fn f[..](..)
改为 fn[..] f(..)
- 数周前,函数定义的类型参数的位置从
fn f[..](..)
改为fn[..] f(..)
,和impl
保持一致。现在,旧的写法被废弃并会收到编译器警告。这一改动可以通过格式化代码自动迁移
5、 typealias
和traitalias
语法更新:改用 as
替代 =
typealias
和traitalias
的语法进行了简化,typealias A = B
和traitalias A = B
这两种写法被废弃,应改为使用typealias B as A
和traitalias B as A
。复杂的typealias
,例如typealias Matrix[X] = Array[Array[X]]
,应改为typealias Array[Array[X]] as Matrix[X]
。这一改动可以通过格式化代码自动迁移
6、废弃多参数 loop
,改用元组参数以保持与 match
一致
- 多参数的
loop
语法被废弃,应改为使用以元组为参数的loop
。这一改动让loop
和match
更一致。MoonBit 编译器在 release 模式下能够通过优化消除掉loop
中元组的开销,因此无需担心这一改动带来性能问题
7、显式实现特征(Trait)新规:即使有默认方法也需 impl
- 对于那些 "每一个方法都有默认实现" 的特征(
trait
),之前,所有类型都会自动实现它们。但现在,即使一个特征的所有方法都有默认实现,也依然需要显式实现。如果没有需要提供自定义实现的方法,可以用impl Trait for Type
来表示 "给Type
实现Trait
,但所有方法都用默认实现"。impl Trait for Type
也可以作为文档/TODO 使用,MoonBit 在看到这种声明时,会自动检查Type
是否实现了Trait
,如果没有实现就报错
8、废弃外部类型 impl
的点调用,改用本地方法扩展
-
之前,给外部类型的
impl
可以在当前包内用.
调用。但这一功能是不重构安全的:上游新增方法会改变下游代码的行为。因此,我们决定废弃这一行为。作为替代,MoonBit 支持了局部地给外部类型定义新方法的功能,语法和普通的方法定义一样。这些给外部类型定义的方法有如下特点:- 它们不能是
pub
的。这是为了保证跨包协作时不会产生冲突 - 如果上游(类型自身所在的包)已经定义了同名方法,编译器会报一个警告
- 在解析方法调用时,本地方法的优先级最高
这一修改之后,
x.f(..)
的解析规则变为(优先级从高到低):- 本地的方法
x
的类型所在的包的方法x
的类型所在的包的impl
- 它们不能是
9、 Json
字面量自动调用 ToJson::to_json
,编写更便捷
- 在
Json
字面量内部,编译器会自动给不是字面量的表达式插入ToJson::to_json
调用,写Json
字面量时会更便捷:
rust
let x = 42
// 之前
let _ : Json = { "x": x.to_json() }
// 现在
let _ : Json = { "x": x }
10、虚拟包支持抽象类型:接口声明,多实现可自定义类型
- 虚拟包(virtual package)功能支持了抽象类型。可以在
.mbti
接口中声明抽象类型,并且不同的实现可以用不同的实际类型来实现接口中的抽象类型
11、 try
可省略:简单表达式错误处理更简洁
- 在处理简单表达式中的错误时,
try
可以省略,直接写f(..) catch { .. }
即可
12、新增保留字警告:未来可能成为关键字
- 新增了一批保留字,它们目前不是关键字,但在未来可能成为关键字。如果在代码中使用这些名字,编译器会提出警告
下列改动目前尚未发布,将在 6.18 MoonBit beta release 之前发布
- 新增了箭头函数语法
(..) => expr
,能极大简化简单匿名函数:
rust
test {
let arr = [ 1, 2, 3 ]
arr
.map(x => x + 1) // 只有一个参数时可以省略括号
.iter2()
.each((i, x) => println("\{i}: \{x}"))
}
- 矩阵函数功能被废弃,以精简语法。形如
fn { .. => expr }
的矩阵函数可以改为箭头函数,其他矩阵函数应改为显式的fn
和match
- 之前,可以使用
xx._
语法来将 new type 转化为其实际表示。但这一语法和 partial application 语法(_.f(..)
)过于相似,有视觉歧义。因此,xx._
语法被废弃,相应的,编译器会给每个 new type 自动生成一个.inner()
方法,代替原本的._
。这一改动可以通过格式化代码自动完成迁移 - 对于一些比较模糊/不够广为人知的运算符优先级组合,例如
<<
和+
,MoonBit 现在会产生警告。手动或者通过格式化代码加上括号来明确计算顺序即可消除警告 - 新引入了
letrec
和and
关键字用于声明 local 互递归函数,比如:
rust
fn main {
letrec even = fn (x: Int) { ... } // anonymous function
and odd = x => ... // arrow function
}
等号右手侧只能是函数形式的值,比如匿名函数或者箭头函数,之前使用 fn
声明的隐式互递归写法会被 deprecated,不过自递归函数依然可以用 fn
进行声明。
fnalias
不再能用于创建非函数值的别名。对于非函数类型的值,可以用let
来创建别名
标准库更新
1、错误多态支持:高阶函数现可接受带错误的回调
- 利用新的错误多态功能,标准库中的许多高阶函数如
Array::each
现在可以接受带错误的回调函数了
工具链更新
main
包中支持写测试。moon test
会运行main
包中的测试,moon run
则会运行main
函数- IDE codelens 支持运行文档中的测试
moon test
和moon check
现在默认会包含文档中的测试
经过深度打磨与社区反馈的持续优化,MoonBit Beta 版本将于6月18日正式发布,迈入语言稳定阶段,因此 MoonBit 双周报从下期起改为月报,请各位用户持续关注本专栏内容。