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