Kotlin學習(三)函數

Kotlin函數


1.函數聲明

kotlin中的函數用fun聲明

fun test(a : Int){
    
}
2.中綴符號

滿足以下條件(成員函數或者擴展函數,只有一個參數,使用infix關鍵詞進行標記)的,函數可以通過使用infix修飾的中綴符號調用

 infix fun Int.shl(x :Int){

}
1 shl 2
3.參數&默認參數

函數接收參數 使用(形參 :參數類型)這種方式。這點與java不同

kotlin函數的參數可以指定默認值

fun test(string : String = "str",int : Int =0){
    
}

在調用時候,如果參數未傳入就會使用指定的默認值

這種特性類似java中的方法重載,在調用時候如果不傳入參數,就會直接使用默認值。

4.命名參數

命名參數可以增加函數的可讀性,但是java不能使用命名參數這種方式來調用kotlin的函數

fun test(name :String = "zhangsan" ,age : Int =12){
    
}
test("lisi")
test("wangwu",16)
test(name = "zhaoliu",age = 18)

命名參數 就是在調用的時候使用 (形參名 = value)這種方法來傳值。如果參數命名比較好的話,增加代碼的可讀性

5.不帶返回值的參數

如果函數不會返回任何值,那么返回值類型就是Unit。Unit是一個只有唯一值Unit的類型。這個類型可以被省略

fun test(name :String?) : Unit{
     //...
 }
 fun test(name :String?){
     //...
 }
6.單表達式函數

當函數返回的只是單個表達式的時候,可以省略大括號,并在=后面跟上表達式

fun testAdd(a: Int, b: Int) = a + b
7.變長參數

kotlin中也存在變長參數 與java中的變長參數類似 (使用vararg修飾符標記 通常是最后一個參數)

fun printVararg(vararg strs :String?){
        for (str in strs){
            println("str=$str")
        }
    }
    
printVararg("zhangsan","lisi","wangwu")
// public void printVararg(String... strs){
// java中的變長參數
//   }

函數中只有一個參數可以被標記為vararg。如果vararg參數不是最后一個,后面的參數需要通過命名函數進行傳值。

調用變長參數的時候,我們可以一個一個的傳遞參數,或者使用*前綴操作符傳遞一個array當作參數

val a = arrayListOf<String>("zhangsan", "lisi", "wangwu")

printVararg(*a)//變長參數直接傳入array
8.函數范圍

Kotlin中的函數可以在文件頂級聲明(也就是說不用創建一個類來持有)
除此之外,函數也可以定義為局部函數,作為成員函數或者擴展函數

fun test(name: String) {
        var mName = name
        fun test(name: String, age: Int) {
            if (name == mName) {
                return
            }
            println("name = $name,age = $age")
        }
        test("zhangsan",12)//調用內部函數
    }

局部函數可以訪問外部函數的局部變量

9.擴展函數

在kotlin中,擴展函數是指可以通過在一個類上增加一個方法,該類以及其子類都可以使用。

//如果有同名同參數的成員函數 和 擴展參數時,必定調用成員函數
//為什么要這么做?我們可以通過擴展類的方法方便我們的直接調用,而不是通過定義一個工具類來調用方法
fun Context.toast(message :String,duration : Int = Toast.LENGTH_SHORT){
        Toast.makeText(this,message,duration).show()
    }

同樣 Kotlin也可以擴展參數

public var TextView.text : CharSequence
        get() = text
        set(value) {
            text = value
        }


高階函數

1.高階函數就是一個能接收函數作為參數并返回一個函數的函數。

//高階函數 可以接收一個函數作為參數

    fun doPrintBeforeAndAfterFunction(doSth: () -> Unit) {//其中doSth是參數名 ()里是參數,這里是沒有傳參數,Unit是返回值
        println(TAG, "before do sth -->")
        doSth()
        println(TAG, "after do sth -->")
    }
    //調用 傳入一個字面函數
     doPrintBeforeAndAfterFunction({ doSth() })
     
      fun doSth() {
        println("$TAG,this is a method ,i will do sth before and after this method")
    }

字面函數或者函數表達式就是一個匿名函數。就是沒有聲明的函數

2.內聯函數

高階函數會帶來一些運行時的效率損失:每一個函數都是一個對象,內存分配(對于函數對象和類)和虛擬調用會引入運行時間開銷。

內聯可能導致生成的代碼增加(內聯在編譯器生成代碼),但是如果我們使用得當(不內聯大函數),它將在性能上有所提升。
(非內聯函數在傳入lambda表達式后會生成一個對象,并作虛擬調用 。而使用內聯函數后在編譯器就會把內聯函數的代碼生成到調用的位置。這樣在運行時就不會再生成對象而是直接運行。這樣會減少開銷但是也會增加代碼量,要慎重使用)

如果內聯函數的某些參數不需要使用內聯,可以用noinline來修飾,這樣在編譯期就不會對該參數進行內聯

內聯函數使用inline關鍵字修飾
比如Kotlin標準函數with

inline fun <T> with(t: T,body :T.()->Unit){
        t.body()
    }

這個函數接收一個對象和一個函數,它的實現是把接收的函數作為傳入對象的擴展函數來使用。這樣在函數內部就可以使用傳入對象的屬性和方法。等于擴展了傳入對象
這個函數通常用于針對同一個對象做很多操作的時候。可以簡化代碼

內聯函數與普通的函數有點不同。一個內聯函數會在編譯的時候被替換
  掉,而不是真正的方法調用。這在一些情況下可以減少內存分配和運行時
  開銷。舉個例子,如果我們有一個函數,只接收一個函數作為它的參數。
  如果是一個普通的函數,內部會創建一個含有那個函數的對象。另一方
  面,內聯函數會把我們調用這個函數的地方替換掉,所以它不需要為此生
  成一個內部的對象。
//該函數可以作為模版函數,處理Android的版本兼容問題
inline fun supportLollipop(code : ()->Unit){
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP){
            code()
        }
    }
    
      supportLollipop {
            //doSth when version  higher than LOLLIPOP
        }

Lambda表達式


在kotlin中,lambda表達式就是一個匿名函數,是Function接口的實現。(最多接受22個參數。。)表達式的寫法如下:

lambda 表達式總是被大括號括著,
其參數(如果有的話)在 -> 之前聲明(參數類型可以省略),
函數體(如果存在的話)在 -> 后面。
{ string -> println("$string,lambda") }

參考資料:https://www.kotliner.cn/2017/02/13/細說%20Lambda%20表達式/

函數相關,操作符重載:https://www.kotliner.cn/2017/04/07/KotlinPrimerFunction/

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容