Kotlin的顯式類型聲明是:java
val sum = { x: Int, y: Int -> x + y }
val action = { println(42) }
// 有兩個Int型參數和Int型返回值的函數
val sum: (Int, Int) -> { x, y -> x + y }
// 沒有參數和返回值的函數
val action(): -> Unit = { println(42) }
複製代碼
聲明函數類型,須要將函數參數類型放在括號中,緊接着是一個箭頭和函數的返回類型,以下:markdown
(Int, String) -> Unit
|- 參數類型 -| |- 返回類型 -|
複製代碼
Unit
類型用於表示函數不返回任何有用的值。在聲明一個普通的函數時,Unit類型的返回值是能夠省略的,可是一個函數類型聲明老是須要一個**顯式
的返回類型**,因此在這種場景下**Unit
是不能省略**的。app
函數類型的返回值是可空類型
& 函數自己可空
ide
var canReturnNull: (Int?, Int?) -> Int? = { x, y ->
y?.let {
x?.plus(it)
}
}
//測試
println(canReturnNull(1, 2))
println(canReturnNull(null, 2))
//輸出結果
3
null
複製代碼
var funOrNull: ((Int, Int) -> Int) ? = null
//測試
println(funOrNull?.let { it(1, 2) })
//輸出結果
null
複製代碼
**注意:**若是省略了括號,聲明的將會是一個返回值可空的函數類型,而不是一個可空的函數類型的變量.函數
注意該函數自己可空時調用須要使用**
?
類型**測試
// 定義一個函數類型的參數:operation
fun twoAndThree(operation: (Int, Int) -> Int) {
// 調用函數類型的參數
val result = operation(2, 3)
println("The result is $result")
}
fun twoAndThreeTest() {
twoAndThree{ a, b -> a + b }
twoAndThree{ a, b -> a * b }
}
// 輸出結果
The result is 5
The result is 6
複製代碼
調用做爲參數的函數和調用普通函數的語法是同樣的:把括號放在函數名後
,並把參數放在括號內
。ui
函數聲明的示意圖1: spa
filter
函數以一個判斷式做爲參數。判斷式的類型是一個函數,以字符
做爲參數
並返回boolean類型
的值。若是要讓傳遞給判斷式的字符出如今最終返回的字符串中,判斷式須要返回true,反之返回false。code
fun String.filter(predicate: (Char) -> Boolean): String {
val result = StringBuilder()
for(index in 0 until length) {
val element = get(index)
// 調用做爲參數傳遞給「predicate」的函數
if(predicate(element)) result.append(element)
}
return result.toString()
}
fun stringFilterTest() {
// 傳遞一個lambda做爲「predicate」參數
println("abcABC123".filter {
it in 'a' .. 'z'
})
}
// 輸出結果
abc
複製代碼
函數類型被聲明爲普通的接口:一個函數類型的變量時FunctionN接口的一個實現。Kotlin標準庫定義了一系列的接口,這些接口對應於不一樣參數樹立的函數:Function0(沒有參數的函數)、Function1<P1, R>(一個參數的函數),等等。每一個接口定義了一個invoke方法,調用這個方法就會執行函數。orm
一個函數類型的變量就是實現了對應的**FunctionN
接口的實現類的實例**,實現類的**invoke
**方法包含了lambda函數體。
/* kotlin 聲明 */
fun processTheAnswer(f: (Int) -> Int) {
println(f(42))
}
/* Java */
// 調用processTheAnswer方法
// 在Java代碼中使用函數類型(Java8之前)
public static void processTheAnswerTest() {
processTheAnswer(
new Function1<Integer, Integer>() {
@Override
public Integer invoke(Integer number) {
System.out.println(number);
return number + 1;
}
}
);
}
// Java 8
processTheAnswer(number -> number + 1)
複製代碼
在Java中能夠很容易地使用Kotlin標準庫中以lambda做爲參數的擴展函數。
可是要注意:必需要顯式地傳遞一個接受者對象做爲第一個參數:
public void printString() {
List<String> strings = new ArrayList<>();
strings.add("42");
// 能夠在Java代碼中使用Kotlin標準庫中的函數
CollectionsKt.forEach(strings, s -> {
System.out.println(s);
// 必需要顯式地返回一個Unit類型的值
return Unit.INSTANCE;
});
}
複製代碼
在**Java
中,函數或者lambda能夠返回Unit
。但由於在Kotlin中Unit類型是有一個值的,因此須要顯式地返回**它。
注意:一個返回
void
的lambda
不能做爲返回Unit的函數類型的實參! 就像以前的例子中的(String) -> Unit
enum class Delivery { STANDARD, EXPEDITED }
class Order(val itemCount: Int)
fun getShippingCostCalculator( // 聲明一個返回函數的函數 delivery: Delivery): (Order) -> Double {
if(delivery == Delivery.EXPEDITED) {
// 返回lambda
return { order -> 6 + 2.1 * order.itemCount }
}
// 返回lambda
return { order -> 1.2 * order.itemCount }
}
fun getShippingCostCalculatorTest() {
// 將返回的函數保存在變量中
val calculator =
getShippingCostCalculator(Delivery.EXPEDITED)
// 調用返回的函數
println("Shipping costs ${calculator(Order(3))}")
}
// 輸出結果
Shipping costs 12.3
複製代碼
聲明一個返回另外一個函數的函數,須要指定一個函數類型做爲返回類型。
在上述代碼中,getShippingCostCalculator返回了一個函數,這個函數以Order做爲參數並返回一個Double類型的值。
要返回一個函數,須要寫一個return表達式,跟上一個lambda、一個成員引用,或者其餘的函數類型的表達式,好比一個(函數類型的)局部變量。