Kotlin Basic:Standard Extension Functions
How to use Kotlin extension (run, apply, also, let and with)
前言
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時會對程式內使用run、apply、let、also、with感到很困惑,所以在這篇文章內會介紹以上用法,讓大家可以快速駕馭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代表該對象,可以使用let作null檢查。
範例程式碼:
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