初識Kotlin之函式
本章通過介紹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表示式提高了我們的開發效率。值得我們去深入學習。