サーチ…
構文
- fun TypeName.extensionName(params、...){/ * body * /} //宣言
- あなたはジェネリックスを使って宣言することができます。<T> Any> TypeNameWithGenerics <T> .extensionName(params、...){/ * body * /} // Generics
- myObj.extensionName(args、...)//呼び出し
備考
拡張機能は静的に解決されます。つまり、使用する拡張メソッドは、アクセスする変数の参照型によって決まります。実行時に変数の型が何であるかは関係ありません。同じ拡張メソッドが常に呼び出されます。これは、拡張メソッドを宣言しても、実際には受信者タイプにメンバーが追加されないためです。
トップレベルの拡張機能
最上位の拡張メソッドは、クラス内には含まれていません。
fun IntArray.addTo(dest: IntArray) {
for (i in 0 .. size - 1) {
dest[i] += this[i]
}
}
上記の拡張メソッドは、 IntArray
型IntArray
定義されています。拡張メソッドが定義されているオブジェクト( 受信者と呼ばれる)には、キーワードthis
を使用してアクセスすることに注意してください。
この拡張は次のように呼び出すことができます:
val myArray = intArrayOf(1, 2, 3)
intArrayOf(4, 5, 6).addTo(myArray)
潜在的な落とし穴:拡張機能が静的に解決される
呼び出される拡張メソッドは、アクセスされる変数の参照型に基づいてコンパイル時に決定されます。実行時に変数の型が何であるかは関係ありません。同じ拡張メソッドが常に呼び出されます。
open class Super
class Sub : Super()
fun Super.myExtension() = "Defined for Super"
fun Sub.myExtension() = "Defined for Sub"
fun callMyExtension(myVar: Super) {
println(myVar.myExtension())
}
callMyExtension(Sub())
上記の例では、印刷され"Defined for Super"
変数の宣言された型ため、 myVar
あるSuper
。
人間が読める文字列をレンダリングするために長く伸びるサンプル
人間が読める文字列を描画するために、 Int
型またはLong
型の値があれば、
fun Long.humanReadable(): String {
if (this <= 0) return "0"
val units = arrayOf("B", "KB", "MB", "GB", "TB", "EB")
val digitGroups = (Math.log10(this.toDouble())/Math.log10(1024.0)).toInt();
return DecimalFormat("#,##0.#").format(this/Math.pow(1024.0, digitGroups.toDouble())) + " " + units[digitGroups];
}
fun Int.humanReadable(): String {
return this.toLong().humanReadable()
}
次に簡単に使用されます:
println(1999549L.humanReadable())
println(someInt.humanReadable())
サンプルJava 7+パスクラスの拡張
拡張メソッドの一般的な使用例は、既存のAPIを改善することです。 Java 7+ Path
クラスにexist
、 notExists
、およびdeleteRecursively
を追加exist
例を次に示します。
fun Path.exists(): Boolean = Files.exists(this)
fun Path.notExists(): Boolean = !this.exists()
fun Path.deleteRecursively(): Boolean = this.toFile().deleteRecursively()
この例でこれを呼び出すことができます:
val dir = Paths.get(dirName)
if (dir.exists()) dir.deleteRecursively()
拡張機能を使用して読みやすくする
Kotlinでは次のようなコードを書くことができます:
val x: Path = Paths.get("dirName").apply {
if (Files.notExists(this)) throw IllegalStateException("The important file does not exist")
}
しかし、 apply
の使用は、あなたの意図と同じくらい明確ではありません。アクションの名前を変更してより自明なものにするために、同様の拡張機能を作成することが時々明確になります。これは手の届かないようにすべきではありませんが、確認のような非常に一般的な処置のために:
infix inline fun <T> T.verifiedBy(verifyWith: (T) -> Unit): T {
verifyWith(this)
return this
}
infix inline fun <T: Any> T.verifiedWith(verifyWith: T.() -> Unit): T {
this.verifyWith()
return this
}
コードを次のように書くことができます:
val x: Path = Paths.get("dirName") verifiedWith {
if (Files.notExists(this)) throw IllegalStateException("The important file does not exist")
}
これは、ラムダパラメータ内で何を期待するかを人々に知らせます。
verifiedBy
型パラメータT
と同じであることに注意してくださいT: Any?
null可能な型でもそのバージョンの拡張機能を使用できることを意味します。ただし、 verifiedWith
はnullを指定できません。
ISO 8形式の文字列をレンダリングするためのJava 8 Temporalクラスの拡張サンプル
この宣言で:
fun Temporal.toIsoString(): String = DateTimeFormatter.ISO_INSTANT.format(this)
これで簡単に次のことができます:
val dateAsString = someInstant.toIsoString()
コンパニオンオブジェクトへの拡張関数(静的関数の出現)
クラスを拡張する場合は、静的関数の場合(たとえば、 Something
クラスのstatic looking関数fromString
追加するなど)は、クラスにコンパニオンオブジェクトがあり、その拡張関数がコンパニオンオブジェクトで宣言されている場合にのみ機能します:
class Something {
companion object {}
}
class SomethingElse {
}
fun Something.Companion.fromString(s: String): Something = ...
fun SomethingElse.fromString(s: String): SomethingElse = ...
fun main(args: Array<String>) {
Something.fromString("") //valid as extension function declared upon the
//companion object
SomethingElse().fromString("") //valid, function invoked on instance not
//statically
SomethingElse.fromString("") //invalid
}
遅延拡張プロパティの回避策
あなたが計算するのに高価な拡張プロパティを作成したいとします。したがって、KotlinのKT-9686とKT- 13053で説明されているように、 レイジープロパティデリゲートを使って計算をキャッシュし、現在のインスタンス( this
)を参照することはできません。ただし、ここには公式の回避策があります 。
この例では、拡張プロパティはcolor
です。これは明示的なcolorCache
を使用しています。 this
はlazy
が必要でないため、 this
と共に使用できます:
class KColor(val value: Int)
private val colorCache = mutableMapOf<KColor, Color>()
val KColor.color: Color
get() = colorCache.getOrPut(this) { Color(value, true) }
簡単な参照のための拡張コードからの表示
ビューを作成した後は、参照ビューの拡張機能を使用することができます。
Anko図書館によるオリジナルのアイデア
拡張機能
inline fun <reified T : View> View.find(id: Int): T = findViewById(id) as T
inline fun <reified T : View> Activity.find(id: Int): T = findViewById(id) as T
inline fun <reified T : View> Fragment.find(id: Int): T = view?.findViewById(id) as T
inline fun <reified T : View> RecyclerView.ViewHolder.find(id: Int): T = itemView?.findViewById(id) as T
inline fun <reified T : View> View.findOptional(id: Int): T? = findViewById(id) as? T
inline fun <reified T : View> Activity.findOptional(id: Int): T? = findViewById(id) as? T
inline fun <reified T : View> Fragment.findOptional(id: Int): T? = view?.findViewById(id) as? T
inline fun <reified T : View> RecyclerView.ViewHolder.findOptional(id: Int): T? = itemView?.findViewById(id) as? T
使用法
val yourButton by lazy { find<Button>(R.id.yourButtonId) }
val yourText by lazy { find<TextView>(R.id.yourTextId) }
val yourEdittextOptional by lazy { findOptional<EditText>(R.id.yourOptionEdittextId) }