Bővítési módszerek Kotlinban

1. Bemutatkozás

Kotlin bevezeti a kiterjesztési módszerek koncepcióját - amelyek azok praktikus módja a meglévő osztályok új funkciókkal való kibővítésének öröklés vagy a Decorator minta bármilyen formájának felhasználása nélkül - a kiterjesztés meghatározása után. lényegében használhatjuk - mivel az eredeti API része volt.

Ez nagyon hasznos lehet a kódunk könnyen olvasható és karbantarthatóvá tételében, mivel olyan módszereket adhatunk hozzá, amelyek specifikusak az igényeink számára, és amelyek az eredeti kód részét képezik, még akkor is, ha nincs hozzáférésünk a források.

Például XML menekülést kell végrehajtanunk a Húr. A szokásos Java-kódban meg kell írnunk egy módszert, amely ezt végre tudja hajtani, és nevezzük:

String escaped = escapeStringForXml (input);

Míg Kotlin-ben írták, a részletet a következővel lehetne helyettesíteni:

val megszökött = input.escapeForXml ()

Ez nem csak könnyebben olvasható, de az IDE-k ugyanúgy felajánlhatják a módszert automatikus kiegészítésként, mintha egy szabványos módszer lenne a Húr osztály.

2. A könyvtár kiterjesztésének szokásos módszerei

A Kotlin Standard Library néhány kiterjesztési módszerrel érkezik.

2.1. Bővítési módszerek kontextusának beállítása

Néhány általános kiterjesztés létezik, és alkalmazásunk minden típusára alkalmazható. Ezeket fel lehet használni a kód megfelelő kontextusban történő futtatásának biztosítására, és bizonyos esetekben annak biztosítására, hogy egy változó ne legyen null.

Kiderült, hogy nagy valószínűséggel anélkül használjuk a bővítményeket, hogy ezt észrevennénk.

Az egyik legnépszerűbb valószínűleg a let () metódus, amely bármilyen típusú meghívható Kotlinban - adjunk át neki egy függvényt, amelyet a kezdeti értéken hajtunk végre:

val name = "Baeldung" val nagybetű = name .let {n -> n.toUpperCase ()}

Hasonló a térkép() módszer től Választható vagy Folyam osztályok - ebben az esetben átadunk egy függvényt, amely egy adott műveletet átalakító műveletet képvisel Húr felső burkolatú ábrázolásába.

A változó név a hívás vevőjeként ismert mert ez a változó, amelyre a kiterjesztési módszer hat.

Ez nagyszerűen működik a biztonságos hívás operátorral:

val name = talánGetName () val nagybetű = név? .let {n -> n.toUpperCase ()}

Ebben az esetben a blokk átment let () csak akkor változik, ha a változó név nem semleges volt. Ez azt jelenti, hogy a blokkon belül az érték n garantáltan nem semleges. Erről bővebben itt.

Vannak más alternatívák is let () ez az igényeinktől függően hasznos is lehet.

A fuss() a kiterjesztés ugyanúgy működik, mint a let (), de egy vevőt biztosítunk ez a meghívott blokkon belüli érték:

val name = "Baeldung" val nagybetű = name.run {toUpperCase ()}

alkalmaz() ugyanúgy működik, mint fuss(), de visszaad egy vevőt ahelyett, hogy visszaadná az értéket a megadott blokkból.

Használjuk ki alkalmaz() a kapcsolódó hívások láncolásához:

val languages ​​= mutableListOf () languages.apply {add ("Java") add ("Kotlin") add ("Groovy") add ("Python")} .apply {remove ("Python")} 

Figyelje meg, hogyan válik kódunk tömörebbé és kifejezőbbé, és nem kell kifejezetten használni ez vagy azt.

A szintén () a kiterjesztés ugyanúgy működik let (), de ugyanúgy visszaadja a vevőt, mint alkalmaz() csinál:

val languages ​​= mutableListOf () languages.also {list -> list.add ("Java") list.add ("Kotlin") list.add ("Groovy")} 

A takeIf () A kiterjesztés a vevőre ható predikátummal van ellátva, és ha ez az állítmány visszatér igaz majd visszaadja a vevőt vagy nulla egyébként - ez hasonlóan működik, mint egy közös térkép kombinációja() és szűrő() mód:

val language = getLanguageUsed () val coolLanguage = language.takeIf {l -> l == "Kotlin"} 

A takeUnless () kiterjesztése megegyezik a takeIf () de a megfordított predikátum logikával.

val language = getLanguageUsed () val oldLanguage = language.takeUneless {l -> l == "Kotlin"} 

2.2. Bővítési módszerek a gyűjteményekhez

Kotlin nagyszámú kiterjesztési módszert ad hozzá a standard Java Gyűjteményekhez, amelyek megkönnyítik a kódunk használatát.

Ezek a módszerek belül találhatók _Collections.kt, _Ranges.kt, és _Sequences.kt, továbbá _Arrays.kt egyenértékű módszerek alkalmazására Tömbök helyette. (Ne feledje, hogy Kotlinban Tömbök ugyanúgy kezelhető, mint Gyűjtemények)

Túl sok ilyen kiterjesztési módszerről van itt szó, ezért keresse meg ezeket a fájlokat, hogy lássa, mi áll rendelkezésre.

A Gyűjtemények mellett Kotlin jelentős számú kiterjesztési módszert ad hozzá a Húr osztály - meghatározása _Strings.kt. Ezek lehetővé teszik a kezelésünket Húrok mintha karaktergyűjtemények lennének.

Mindezek a kiterjesztési módszerek együttesen lehetővé teszik számunkra, hogy lényegesen tisztább, könnyebben karbantartható kódot írjunk, függetlenül attól, hogy milyen típusú kollekcióval dolgozunk.

3. Bővítési módszereink írása

Szóval, mi van akkor, ha egy osztályt új funkcióval kell kibővítenünk - akár a Java vagy a Kotlin Standard Library-ből, akár egy függő könyvtárból, amelyet használunk?

A kiterjesztési módszereket minden más módszerhez hasonlóan írják, de a vevő osztály a függvénynév részeként kerül megadásra, elválasztva a periódustól.

Például:

fun String.escapeForXml (): Karakterlánc {....}

Ez egy új függvényt fog definiálni escapeForXml kiterjesztése a Húr osztály, lehetővé téve számunkra, hogy a fent leírt módon hívjuk.

Ezen a funkción belül a vevő segítségével érhetjük el ez, ugyanaz, mintha ezt írtuk volna a Húr maga az osztály:

fun String.escapeForXml (): String {adja vissza ezt a .replace ("&", "&") .replace ("<", "", ">")}}

3.1. Általános kiterjesztési módszerek írása

Mi van, ha olyan kiterjesztési módszert akarunk írni, amelyet több típusra, általában akarunk alkalmazni? Csak meghosszabbíthatnánk a Bármi típus, - amely megegyezik a Tárgy osztály Java-ban - de van egy jobb módszer.

A kiterjesztési módszerek alkalmazhatók egy általános és egy konkrét vevőre is:

fun T.concatAsString (b: T): Karakterlánc {adja vissza ezt.String () + b.String ()}

Ez alkalmazható minden olyan típusra, amely megfelel az általános követelményeknek, és a funkción belül ez értéke typeafe.

Például a fenti példa segítségével:

5.concatAsString (10) // lefordítja az "5" -t .concatAsString ("10") // lefordítja az 5.concatAsString ("10") // nem fordítja le

3.2. Infix kiterjesztési módszerek írása

Az Infix módszerek hasznosak a DSL stílusú kódok írásához, mivel lehetővé teszik a módszerek pont és zárójelek nélküli meghívását:

infix fun Number.toPowerOf (kitevő: Szám): Dupla {return Math.pow (this.toDouble (), exponent.toDouble ())}

Ezt ugyanúgy hívhatjuk, mint bármely más infix metódust:

3 toPowerOf 2 // 9 9 toPowerOf 0.5 // 3

3.3. Operátor kiterjesztési módszerek írása

Írhatnánk kiterjesztésként operátor metódust is.

Az operátori módszerek olyanok, amelyek lehetővé teszik számunkra, hogy a teljes metódusnév helyett az operátor gyorsírását használjuk ki - pl plusz operátor metódus meghívható a + operátor:

operátor szórakozás List.times (by: Int): List {return this.map {it * by}}

Ez megint ugyanúgy működik, mint bármely más operátor-módszer:

listOf (1, 2, 3) * 4 // [4, 8, 12]

4. A Kotlin Extension Function meghívása Java-ból

Most nézzük meg, hogyan működik a Java a Kotlin kiterjesztés funkcióival.

Általánosságban elmondható, hogy a Kotlinban definiált minden kiterjesztési módszer elérhető a Java-ban. Nem szabad megfeledkeznünk arról, hogy a szóbelseji formáns metódust még mindig pontokkal és zárójelekkel kell meghívni. Ugyanez az operátor kiterjesztésekkel - nem használhatjuk csak a plusz karaktert (+). Ezek a létesítmények csak itt érhetők el Kotlin.

Azonban nem tudjuk meghívni a Java szabványos Kotlin könyvtárának néhány módszerét, mint például hadd vagy alkalmaz, mert őket jelölik @InlineOnly.

4.1. A Java kiterjesztés funkció láthatósága

Használjuk az egyik korábban definiált kiterjesztési függvényt - String.escapeXml (). A kiterjesztési módszert tartalmazó fájlunk neve StringUtil.kt.

Most, amikor egy kiterjesztési módszert kell meghívnunk a Java-ból, osztálynévvel kell rendelkeznünk StringUtilKt. Ne feledje, hogy hozzá kell adnunk a Kt utótag:

Karakterlánc xml = "szia"; String escapedXml = StringUtilKt.escapeForXml (xml); assertEquals ("szia", ​​escapedXml);

Kérjük, figyeljen az elsőre escapeForXml paraméter. Ez a további argumentum egy kiterjesztési függvény vevő típusa. A legfelső szintű kiterjesztési funkcióval rendelkező Kotlin tiszta Jáva osztály statikus módszerrel. Ezért kell valahogy átadni az eredetit Húr.

És persze, akárcsak bent Jáva, használhatjuk a statikus importálást:

importáljon statikus com.baeldung.kotlin.StringUtilKt. *;

4.2. Beépített Kotlin kiterjesztési módszer meghívása

Kotlin sok beépített kiterjesztési funkcióval segít nekünk könnyebben és gyorsabban írni a kódot. Például ott van a Húr.nagybetűs () módszer, amelyből közvetlenül hívható Jáva:

Karakterlánc neve = "john"; String kapitalizáltNév = StringsKt.capitalize (név); assertEquals ("John", nagybetűsNév);

Azonban, nem hívhatjuk a kiterjesztéses módszereket @InlineOnly tól től Jáva, például:

inline fun T.let (blokk: (T) -> R): R

4.3. A generált Java statikus osztály átnevezése

Azt már tudjuk, hogy a Kotlin kiterjesztési függvény statikus Jáva módszer. Nevezzünk át egy generáltat Jáva osztály annotációval @fájl: JvmName (név: Karakterlánc).

Ezt hozzá kell adni a fájl tetejéhez:

@file: JvmName ("Strings") csomag com.baeldung.kotlin fun String.escapeForXml (): String {adja vissza ezt a .replace ("&", "&") .replace ("<", "", ">" )}

Most, amikor egy kiterjesztési módszert akarunk meghívni, egyszerűen hozzá kell adnunk a Húrok osztály név:

Strings.escapeForXml (xml);

Továbbá hozzáadhatunk statikus importálást:

import statikus com.baeldung.kotlin.Strings. *;

5. Összefoglalás

A kiterjesztési módszerek hasznos eszközök a rendszerben már létező típusok kiterjesztésére - vagy azért, mert nincsenek a szükséges funkciók, vagy egyszerűen a kód bizonyos területeinek könnyebb kezelése.

Láttunk néhány kiterjesztési módszert, amelyek készen állnak a rendszer használatára. Ezenkívül megvizsgáltuk a kiterjesztési módszerek különféle lehetőségeit. Néhány példa erre a funkcióra a GitHub oldalon található.


$config[zx-auto] not found$config[zx-overlay] not found