方法
在 MoonBit 里,方法是关联到某个类型上的顶层函数。
有两种方式来定义方法:
fn method_name(self : T, ..) -> ..
。第一个参数的名字必须是self
,定义出来的方法会被关联到类型T
上fn T::method_name(..) -> ..
,定义出来的方法会被关联到类型T
上
和普通函数相比,方法可以用更灵活的方式来调用:
- 所有方法都可以用
T::method_name(..)
的形式调用 - 方法也可以用
x.method_name(..)
的形式调用,假设x
的类型是T
,这种写法等价于T::method_name(x, ..)
- 用
fn method_name(self : T, ..)
形式声明的方法可以像普通函数一样直接用method_name(..)
的形式调用
之前的章节中已经出现了很多方法,例如 Array::make(..)
和 array.length()
。
关于方法的两种定义方式的不同之处是什么,应该如何选择:
fn method_name(self : T, ..)
声明的方法就是一个普通的顶层函数,所以它可以像普通函数一样直接调用。但这也意味着它不能和其他函数重名。如果一个方法是给它所在的包的一个比较主要的类型定义的,并且不会和其他函数重名,则推荐用fn method_name(self : T, ..)
的形式定义它,这样用户调用时可以省去T::
fn T::method_name(..)
声明的方法会被放到T
这个小命名空间里,所以这种方法只能用T::method_name(..)
或者x.method_name(..)
的方式调用。但相应的,这种方法可以和普通函数以及其他类型的方法重名。所以,这种定义方式可以用来解决名字冲突或简化包的顶层作用域。
type MyInt Int
fn increment(self : MyInt) -> MyInt {
MyInt(self._ + 1)
}
fn MyInt::println(x : MyInt) -> Unit {
println("MyInt(\{x._})")
}
fn main {
let x = MyInt(39)
let y = x.increment() // 用 `.` 语法调用方法
let z = increment(y) // `fn increment(..)` 可以直接调用
let w = MyInt::increment(z) // 也可以用 `T::method_name` 调用
w.println()
MyInt::println(w) // `fn MyInt::println` 不能直接用 `println(..)` 调用
}