Infix
Infix 函数是:
- 如果函数是成员函数或者extension 函数
- 如果只有一个参数
- 标注了infix
// Define extension to Int
infix fun Int.shl(x: Int): Int {
...
}
// call extension function using infix notation
1 shl 2
// is the same as
1.shl(2)
函数默认值
fun read(b: Array<Byte>, off: Int = 0, len: Int = b.size()) {
...
}
如果子类要覆盖父类的方法,函数声明的时候需要沿用父类的默认值,不能重写默认值
//open class A {
open fun foo(i: Int = 10) { ... }
}
class B : A() {
override fun foo(i: Int) { ... } // no default value allowed
}
命名参数
fun reformat(str: String,
normalizeCase: Boolean = true,
upperCaseFirstLetter: Boolean = true,
divideByCamelHumps: Boolean = false,
wordSeparator: Char = ' ') {
...
}
reformat(str,
normalizeCase = true,
upperCaseFirstLetter = true,
divideByCamelHumps = false,
wordSeparator = '_'
)
Varargs
函数参数可以被标记为vararg
,参数会被当做数组:
fun <T> asList(vararg ts: T): List<T> {
val result = ArrayList<T>()
for (t in ts) // ts is an Array
result.add(t)
return result
}
只有一个参数能被标记为vararg
,如果vararg
参数不是最后一个参数,其他参数只能通过命名参数来传递。
局部函数
局部函数是定义在函数内部的函数,它可以访问外部函数的变量
fun dfs(graph: Graph) {
fun dfs(current: Vertex, visited: Set<Vertex>) {
if (!visited.add(current)) return
for (v in current.neighbors)
dfs(v, visited)
}
dfs(graph.vertices[0], HashSet())
}
泛型函数
泛型函数将泛型参数放在函数名之前
fun <T> singletonList(item: T): List<T> {
// ...
}
Extension函数
向已有的对象添加函数,函数里的this代表对象
fun MutableList<Int>.swap(index1: Int, index2: Int) {
val tmp = this[index1] // 'this' corresponds to the list
this[index1] = this[index2]
this[index2] = tmp
}
高阶函数
高阶函数将其他函数作为参数传入
fun <T> lock(lock: Lock, body: () -> T): T {
lock.lock()
try {
return body()
}
finally {
lock.unlock()
}
}
如果最后一个参数是函数,而且传入的是lambda函数,则可以把lambda函数写在括号外,如果传入的是匿名函数,则不能写在括号外:
lock (lock) {
sharedResource.operation()
}
如果lambda函数只有一个参数,可以用it来指代
函数参数需要声明函数的type:
fun <T> max(collection: Collection<T>, less: (T, T) -> Boolean): T? {
var max: T? = null
for (it in collection)
if (max == null || less(max, it))
max = it
return max
}
函数类型里也可以指定参数名称
val compare: (x: T, y: T) -> Int = ...
匿名函数
fun(x: Int, y: Int): Int = x + y
如果是单行的表达式,返回值的类型可以推导出,可以省略,如果是block,那么返回值的类型需要指定,否则就是Unit
lambda表达式的return是退出外围的函数,而匿名函数的return是退出自己
闭包
lambda表达式和匿名函数都可以访问外围作用域的变量,与Java不同的是,Kotlin允许修改闭包里的变量(Java闭包的变量需要声明为final)
带Receiver的字面函数(好难理解)
你可以定义一个函数,指定这个函数的Receiver,Receiver为一个类
sum : Int.(other: Int) -> Int
然后在这个类的实例上调用这个函数
1.sum(2)
inline 函数
inline 之前
lock(l) { foo() }
inline 之后
inline fun lock<T>(lock: Lock, body: () -> T): T {
// ...
}
==>
l.lock()
try {
foo()
}
finally {
l.unlock()
}
inline 会展开调用函数和lambda参数,如果不想lambda参数被展开,可以在lambda参数前加上noinline
inline fun foo(inlined: () -> Unit, noinline notInlined: () -> Unit) {
// ...
}
lambda表达式中不允许使用不带标签的return语句(因为lambda中return是退出外围的函数,这叫non-local return
),但如果lambda是传入到一个inline函数中,则可以return