1.1.50.11. fejezet, Kiterjesztések
A Kotlin lehetővé teszi egy osztály vagy interfész új funkciókkal való bővítését anélkül, hogy örökölnie kellene az osztálytól, vagy olyan tervezési mintákat kellene használnia, mint a Decorator. Ez speciális deklarációkkal, úgynevezett kiterjesztésekkel történik.
fun MutableList<Int>.swap(index1: Int, index2: Int) { val tmp = this[index1] // 'this' corresponds to the list this[index1] = this[index2] this[index2] = tmp } val list = mutableListOf(1, 2, 3) list.swap(0, 2) // 'this' inside 'swap()' will hold the value of 'list'
Ez a kód generikusok alkalmazásával általánosítható:
fun <T> MutableList<T>.swap(index1: Int, index2: Int) { val tmp = this[index1] // 'this' corresponds to the list this[index1] = this[index2] this[index2] = tmp }
open class Shape class Rectangle: Shape() fun Shape.getName() = "Shape" fun Rectangle.getName() = "Rectangle" fun printClassName(s: Shape) { println(s.getName()) } printClassName(Rectangle())
A válasz erre a kódra a Shape
Ha van ugyanolyan nevű és szignatúrájú metódus az osztályban, akkor mindig a metódus hívódik meg, nem íródik felül.
class Example { fun printFunctionType() { println("Class method") } } fun Example.printFunctionType() { println("Extension function") } Example().printFunctionType()
Erre a kódra a válasz a "Class method".
Azonban ha ugyanolyan nevű de eltérő szignatúrájú metódust valósítunk meg, akkor az hívódik meg:
class Example { fun printFunctionType() { println("Class method") } } fun Example.printFunctionType(i: Int) { println("Extension function #$i") } Example().printFunctionType(1)
Ennek a kódnak a kimenete: "Extension function #1".
Nullázható fogadó
fun Any?.toString(): String { if (this == null) return "null" // After the null check, 'this' is autocast to a non-nullable type, so the toString() below // resolves to the member function of the Any class return toString() }
Tulajdonság kiterjesztés
val <T> List<T>.lastIndex: Int get() = size - 1 val House.number = 1 // error: initializers are not allowed for extension properties
Kísérőobjektum-kiterjesztések
Ha egy osztályhoz társobjektum van definiálva, akkor kiterjesztési függvényeket és tulajdonságokat is definiálhat a társobjektumhoz.
class MyClass { companion object { } // will be called "Companion" } fun MyClass.Companion.printCompanion() { println("companion") } fun main() { MyClass.printCompanion() }
A bővítmények hatásköre
Ha definiáljuk az egyik csomagban a getLongestString metódust:
package org.example.declarations fun List<String>.getLongestString() { /*...*/}
akkor azt importálni kell az alkalmazó csomagban a következő képen:
package org.example.usage import org.example.declarations.getLongestString fun main() { val list = listOf("red", "green", "blue") list.getLongestString() }
Bővítmény deklarálása tagként
class Host(val hostname: String) { fun printHostname() { print(hostname) } } class Connection(val host: Host, val port: Int) { fun printPort() { print(port) } fun Host.printConnectionString() { printHostname() // calls Host.printHostname() print(":") printPort() // calls Connection.printPort() } fun connect() { /*...*/ host.printConnectionString() // calls the extension function } }
Bővítményből meghívni a deklaráló osztály metódusát így lehet:
class Connection { fun Host.getConnectionString() { toString() // calls Host.toString() this@Connection.toString() // calls Connection.toString() } }
Öröklődés esetén a következőket érdemes figyelembe venni a bővítményeknél:
open class Base { } class Derived : Base() { } open class BaseCaller { open fun Base.printFunctionInfo() { println("Base extension function in BaseCaller") } open fun Derived.printFunctionInfo() { println("Derived extension function in BaseCaller") } fun call(b: Base) { b.printFunctionInfo() // call the extension function } } class DerivedCaller: BaseCaller() { override fun Base.printFunctionInfo() { println("Base extension function in DerivedCaller") } override fun Derived.printFunctionInfo() { println("Derived extension function in DerivedCaller") } } fun main() { BaseCaller().call(Base()) // "Base extension function in BaseCaller" DerivedCaller().call(Base()) // "Base extension function in DerivedCaller" - dispatch receiver is resolved virtually DerivedCaller().call(Derived()) // "Base extension function in DerivedCaller" - extension receiver is resolved statically }
Láthatóság
A bővítmények az osztályoknál, metódusoknál és tulajdonságoknál meghatározott láthatóságokkal rendelkeznek.
- A hozzászóláshoz be kell jelentkezni