【Kotlin】Kotlin基礎:Standard Extension Functions

Kotlin Basic:Standard Extension Functions

Posted by Tabaco on January 18, 2018

前言

Kotlin 的 extension 是用來為現成的 class 加入新 method 和 attribute。Extension 是用來取代 Java programming 時常寫的 Utils static method。Extension 比 Utils 較佳是 extension 有 IDE 提示和用法較為自然。

舉個例子,在Java內要在已存在的 class 新增 extension function,你可能會這樣寫:

class Util {
  public static final boolean isNumeric(String receiver) {
    return reveiver.matches("\\d+");
  }
}
...

String myString = ...;

if(Util.isNumeric(myString)) ...

而Kotlin則可以用下面的程式碼來新增 extension function:

fun String.isNumeric(): Boolean {
  return this.matches("\\d+".toRegex())
}
...

val myString = ...

if(myString.isNumeric()) ...

是不是感覺簡單多了!

在Kotlin也有許多內建的 extension function,剛開始學習Kotlin時會對程式內使用runapplyletalsowith感到很困惑,所以在這篇文章內會介紹以上用法,讓大家可以快速駕馭Kotlin。

Run

public inline fun <T, R> T.run(block: T.() -> R): R = block()

run 可以在任何型態 T 執行,並返回最後一行的返回值或者指定return表達式。

思考看看底下這個範例:

val generator = PasswordGenerator()
generator.seed = "someString"
generator.hash = {s -> someHash(s)}
generator.hashRepititions = 1000

val password: Password = generator.generate()

當建立PasswordGenerator需要對多個attribute作設定,因此還沒使用run之前需要打好幾次generator,所以可以用run修改成以下程式碼:

val password: Password = PasswordGenerator().run {
       seed = "someString"
       hash = {s -> someHash(s)}
       hashRepetitions = 1000

       generate()
   }

apply

public inline fun <T> T.apply(block: T.() -> Unit): T { block(); return this }

apply的用法跟run很像,但有一點不同的是apply的返回值永遠都為自身對象,在函式區塊內可以用this代表自身對象。 用以下範例示範如何使用apply建立一個Intent:

// 普通建立Intent方法
fun createIntent(intentData: String, intentAction: String): Intent {
    val intent = Intent()
    intent.action = intentAction
    intent.data=Uri.parse(intentData)
    return intent
}

// 使用apply建立Intent方法
fun createIntent(intentData: String, intentAction: String) =
        Intent().apply { action = intentAction }
                .apply { data = Uri.parse(intentData) }

let

public inline fun <T, R> T.let(block: (T) -> R): R = block(this)

let將會返回最後一行的返回值或者指定return表達式,在函式區塊內使用it代表該對象,可以使用letnull檢查。

範例程式碼:

val original = "abc"

original.let {
    println("The original String is $it") // "abc"
    it.reversed() 
}.let {
    println("The reverse String is $it") // "cba"
    it.length  
}.let {
    println("The length of the String is $it") // 3
}

let的返回值是函式區塊內的最後一個對象,它的值和類型都可以被改變,如上列程式碼中第一次let返回值為String型態的cba,第二次let返回值則變更為Int型態的數值3

also

public inline fun <T> T.also(block: (T) -> Unit): T { block(this); return this }

Kotlin 1.1版才新增的 extension function,also將會返回值永遠都為自身對象,在函式區塊內使用it代表該對象。

val original = "abc"

original.also {
    println("The original String is $it") // "abc"
    it.reversed() 
}.also {
    println("The reverse String is ${it}") // "abc"
    it.length  
}.also {
    println("The length of the String is ${it}") // "abc"
}

從上列程式碼得知不管調用多少次also都是返回original原本的String型態。

with

public inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()

with函式跟前面幾個函式使用方法有點不同,因為它並不是以 extension 的形式存在的,在函式區塊內可以透過this指定該對象,with將會返回最後一行的返回值或者指定return表達式。

範例:

val a = with("string") {
    println(this)
    3
}
println(a)

執行結果:

string
3

參考資料