前言
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
參考資料
- Kotlin Basics: Standard Extension Functions
- Standard.kt
- Mastering Kotlin standard functions: run, with, let, also and apply