本章經過介紹Kotlin的基本函數,默認參數函數,參數不定長函數,尾遞歸函數,高階函數,Lamdba表達式。來對Kotlin函數作進一步瞭解。將上一篇的Kotlin變量的知識得以運用。Kotlin變量html
Kotlin中是經過關鍵字fun聲明函數。和變量同樣,返回值類型放在名稱後面,並用":"冒號分開。Kotlin函數默認修飾符public,且能夠在文件頂層聲明。其格式以下程序員
fun 函數名(變量): 返回值類型 { }
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
還一個語法問題,子類繼承父類的參數默認值函數後,是不容許重寫的函數爲其參數指定默認值。好在這種狀況編譯器會提示錯誤。ide
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中很是常見。this
// 函數做爲參數 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
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有多麼強大了。
擴展函數指的是在已有類中添加新的方法,且不會對原類作修改。
fun receiverType.funName(params): returnType{ /*代碼塊*/ }
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表達式提升了咱們的開發效率。值得咱們去深刻學習。