本章通過介紹Kotlin的基本函數,默認參數函數,參數不定長函數,尾遞歸函數,高階函數,Lamdba表達式。來對Kotlin函數做進一步了解。將上一篇的Kotlin變量的知識得以運用。Kotlin變量
Kotlin函數簡介
Kotlin中是通過關鍵字fun聲明函數。和變量一樣,返回值類型放在名稱后面,並用":"冒號分開。Kotlin函數默認修飾符public,且可以在文件頂層聲明。其格式如下
fun 函數名(變量): 返回值類型 {
}
Kotlin常見函數
基礎函數
fun getValue(v: Int): Int {
return v
}
當函數不需要返回任何值時,可以將返回值類型定義成Unit,也可以不顯式返回。
fun setValue(v: Int) {
}
參數默認值函數
函數的參數可以有默認值,當函數調用者不給默認參數賦值時,函數體就使用參數的默認值。這樣可以減少很多方法重載的代碼量。
fun setValue(x: Int, y: Int = 10): Int {
retunr x + y
}
setValue(10) -----> 20
setValue(10, 20) -----> 30
參數默認值函數固然好用。但是由於每個人的編程習慣和編程水平的不同。項目中出現下面的代碼的概率還不低。通過程序打印的結果可以看出,輸出的結果並不是我們預期的21.2,而且10。說明編譯器是調用的是第一個函數。
fun main(args: Array<String>) {
println(setValue(10)) -----> 10
}
fun setValue(x: Int) = x
fun setValue(x: Int, y: Int = 10, z: Double = 1.2) = x + y + z
還一個語法問題,子類繼承父類的參數默認值函數后,是不允許重寫的函數為其參數指定默認值。好在這種情況編譯器會提示錯誤。
open class FatherClass {
open fun setValue(x: Int, y: Int = 10, z: Double = 1.2) = x + y + z
}
class SunClass: FatherClass() {
// An overriding function is not allowed to specify default values for its paramete
override fun setValue(x: Int, y: Int, z: Double) = x + y + z
}
單表達式函數
若函數體只是單個表達式時,可以省略花括號並用"=" 指定代碼體。了解一下即可,至少遇到了不要驚訝。
fun setValue(x: Int, y: Int) = x + y
不定長參數函數
有很多場景函數的變量的個數是不確定。Java是通過三個點"..."表示不定個數的參數。而Kotlin需要通過關鍵字vararg定義參數,表示函數的參數個數不確定。
fun mathPlus(vararg arguments: Any): Any {
var result: BigDecimal = BigDecimal.ZERO
arguments.map {
result = result.plus(BigDecimal(it.toString()))
}
return result
}
mathPlus(1,2,3,4.5) ------> 10.5
尾遞歸函數
Kotlin支持尾遞歸的編程風格。允許一些算法可以通過循環而不是遞歸解決問題,避免堆棧溢出導致的系統不穩定。Kotlin還提供了尾遞歸優化的關鍵字tailrec。但要符合 tailrec 修飾符的條件,需要函數必須將其自身調用作為它執行的最后一個操作。我們用求階乘的代碼演示尾遞歸。
// 尾遞歸,可以保證堆棧不溢出,但是還要考慮數據類型的取值范圍
tailrec fun fibolaAlgorithm(num: Int, result: Int): Int {
println("剩余遞歸次數 : $num \t 計算結果: $result")
return if (num == 0) {
1
} else {
fibolaAlgorithm(num - 1, result + num)
}
}
高階函數
高階函數是Kotlin的一大亮點,高階函數是可以將函數用作參數或返回值的函數。下面代碼中,forEach是函數,println也是一個方法,通過雙冒號將函數作為一個參數傳遞。這種用法在Kotlin中非常常見。
// 函數作為參數
fun paramFun() {
val list = listOf(1, 2)
list.forEach(::println)
}
// 函數作為返回值
fun returnFun(): (Int, Int) -> Int {
return { j, i -> j + i }
}
println(returnFun().invoke(1,2))
閉包函數
閉包就是能夠讀取其他函數內部變量的函數。當我們的程序希望讀取到函數的內部變量,或者希望被訪問的變量保存在內存中。就需要用到閉包。這下這段代碼算是比較典型的閉包函數。
fun closureMethod(i: Int): () -> Int {
var memoryValue = 1
return fun(): Int {
return i + memoryValue++
}
}
val closure = closureMethod(0)
println(closure()) ------> 1
println(closure()) ------> 2
Kotlin Lamdba表達式
Lambda表達式的本質其實是匿名函數,底層還是通過匿名函數來實現。Lambda的出現確實是減少了代碼量,同時代碼變得更加簡潔明了。
Lamdba語法結構
val/var 變量名: (參數類型,參數類型,...) -> 返回值類型 = { 參數1,參數2,... -> 代碼塊 }
在這個基礎上,Kotlin還支持智能推導模式,讓代碼更簡單,讓讀者更摸不清頭腦,新手看這種代碼一定覺得怪怪的。注意:實參並沒有用括號括起來,而是通過箭頭將實參和代碼塊區分開。
// 無參: val/var 變量名: () -> 返回值類型 = { 代碼塊 },
val a:() -> Int = { 10 }
// 有參: val/var 變量名: (變量類型...) -> 返回值類型 = { 參數1,參數2, ... -> 操作參數的代碼 }
val b: (Int, Int) -> Int = {x, y -> x + y }
// 推導: val/var 變量名 = { 參數1: 類型, 參數2: 類型, ... -> 操作參數的代碼 }
val c = { x: Int, y: Int -> x + y }
println(c(1,2)) ------> 3
Lamdba和集合可以擦出愛情的火花,下一章介紹Kotlin集合函數API(filter,map,groupBy,maxBy...)時,你就知道Lamdba有多么強大了。
Kotlin 擴展函數
擴展函數指的是在已有類中添加新的方法,且不會對原類做修改。
fun receiverType.funName(params): returnType{
/*代碼塊*/
}
- receiverType:擴展函數的接收者,也就是函數擴展的對象
- returnType: 擴展函數的返回值類型
- funName:擴展函數的名稱
- params:擴展函數的參數,可以為NULL
fun Int.extensionFun(i: Int): Int {
return this + i
}
println(10.extensionFun(20)) ------> 30
因為擴展函數是可以讓程序員自己添加的,出現函數重名的情況非常常見。所以,如果遇到重名的情況。可以在導入包時,通過 as 關鍵字進行改名。注意:改名后不能再用原來的函數名。
import com.kotlin.demo.extensionFun as aliasITDragon
fun main(args: Array<String>) {
println(1.aliasITDragon(2)) ------> 3
}
如果擴展函數只有一個變量,我們可以使用中綴符號( infix 關鍵字)修飾函數,位於fun關鍵字之前。
infix fun Int.extensionFun(i: Int): Int {
return this + i
}
println(10 extensionFun 20) ------> 30
println(10.extensionFun(20)) ------> 30
文章到這里就介紹了,Kotlin提供的擴展函數,Lamdba表達式提高了我們的開發效率。值得我們去深入學習。