Sök…


Syntax

  • fun TypeName.extensionName (params, ...) {/ * body * /} // Deklaration
  • fun <T: Any> TypeNameWithGenerics <T> .extensionName (params, ...) {/ * body * /} // Declaration with Generics
  • myObj.extensionName (args, ...) // invocation

Anmärkningar

Tillägg löses statiskt . Detta innebär att den förlängningsmetod som ska användas bestäms av referenstypen för den variabel du har åtkomst till; det spelar ingen roll vad variabelens typ är vid körning, samma förlängningsmetod kommer alltid att kallas. Detta beror på att deklarerande av en förlängningsmetod faktiskt inte lägger till en medlem i mottagartypen .

Toppnivåförlängningar

Förlängningsmetoder på toppnivå ingår inte i en klass.

fun IntArray.addTo(dest: IntArray) {
    for (i in 0 .. size - 1) {
        dest[i] += this[i]
    }
}

Ovanför en förlängningsmetod definieras för typen IntArray . Observera att objektet för vilket förlängningsmetoden definieras (kallas mottagaren ) nås med hjälp av nyckelordet this .

Denna tillägg kan kallas så:

val myArray = intArrayOf(1, 2, 3)
intArrayOf(4, 5, 6).addTo(myArray)

Potentiell fallgrop: Förlängningar löses statiskt

Den förlängningsmetod som ska kallas bestäms vid sammanställningstiden baserat på referenstypen för den variabel som åtkomst till. Det spelar ingen roll vad variabelens typ är vid körning, samma förlängningsmetod kommer alltid att kallas.

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())

Exemplet ovan kommer att skriva ut "Defined for Super" , eftersom den deklarerade typen av variabeln myVar är Super .

Prov som sträcker sig långt för att göra en mänsklig läsbar sträng

Med tanke på något värde av typen Int eller Long att göra en mänsklig läsbar sträng:

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()
}

Sedan lätt att använda som:

println(1999549L.humanReadable())
println(someInt.humanReadable())

Exempel på utvidgning av Java 7+ sökväg

Ett vanligt användningsfall för förlängningsmetoder är att förbättra ett befintligt API. Här är exempel på att lägga till exist , notExists och deleteRecursively till Java 7+ Path Klass:

fun Path.exists(): Boolean = Files.exists(this)
fun Path.notExists(): Boolean = !this.exists()
fun Path.deleteRecursively(): Boolean = this.toFile().deleteRecursively()

Som nu kan åberopas i detta exempel:

val dir = Paths.get(dirName)
if (dir.exists()) dir.deleteRecursively()

Använda förlängningsfunktioner för att förbättra läsbarheten

I Kotlin kan du skriva kod som:

val x: Path = Paths.get("dirName").apply { 
    if (Files.notExists(this)) throw IllegalStateException("The important file does not exist")
}

Men användningen av apply är inte så tydlig när det gäller din avsikt. Ibland är det tydligare att skapa en liknande förlängningsfunktion för att i själva verket byta namn på handlingen och göra den mer självklar. Detta bör inte tillåtas komma ur handen, men för mycket vanliga åtgärder som verifiering:

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
}

Du kan nu skriva koden som:

val x: Path = Paths.get("dirName") verifiedWith {
    if (Files.notExists(this)) throw IllegalStateException("The important file does not exist")
}

Låt oss nu veta vad de kan förvänta sig inom lambda-parametern.

Observera att typparametern T för verifiedBy är samma som T: Any? vilket betyder att även nollbara typer kommer att kunna använda den versionen av tillägget. Även om verifiedWith kräver icke-nullable.

Exempel på utvidgning av Java 8 Temporal klasser för att göra en ISO-formaterad sträng

Med denna förklaring:

fun Temporal.toIsoString(): String = DateTimeFormatter.ISO_INSTANT.format(this)

Du kan nu helt enkelt:

val dateAsString = someInstant.toIsoString()

Förlängningsfunktioner till Companion Objects (utseende av statiska funktioner)

Om du vill utöka en klass som om du är en statisk funktion, till exempel för klassen Something lägg till statisk utseende-funktion från fromString , kan detta bara fungera om klassen har ett följeslagareobjekt och att förlängningsfunktionen har deklarerats på ledsagarobjektet :

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
}

Lös lösning för fastighetsförlängning

Antag att du vill skapa en tilläggsegenskap som är dyr att beräkna. Således vill du cache beräkningen genom att använda den lata egenskapens delegat och hänvisa till nuvarande instans ( this ), men du kan inte göra det, vilket förklaras i Kotlins utgåvor KT-9686 och KT-13053 . Det finns emellertid en officiell lösning här .

I exemplet är förlängningsegenskapen color . Den använder en tydlig colorCache som kan användas med this eftersom det inte är lazy :

class KColor(val value: Int)

private val colorCache = mutableMapOf<KColor, Color>()

val KColor.color: Color
    get() = colorCache.getOrPut(this) { Color(value, true) }

Tillägg för enklare referens Visa från kod

Du kan använda tillägg för referensvy, inte mer pannplatta efter att du skapat vyerna.

Originalidé är av Anko Library

Extensions

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

Användande

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) }


Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow