Menu
Coddy logo textTech

Funkcje rozszerzające

Część sekcji Programowanie obiektowe ścieżki Kotlin w Coddy. Lekcja 30 z 57.

Funkcja rozszerzająca dodaje funkcję do istniejącego typu bez zmiany kodu źródłowego tego typu. Jej nazwa jest zapisywana po typie odbiorcy, a wewnątrz niej this odnosi się do odbiorcy, ale można je też pominąć:

fun String.shout() = uppercase() + "!"
fun Int.isEven() = this % 2 == 0

Wewnątrz main:

println("hello".shout())
println(7.isEven())
println(listOf(1, 2, 3, 4).count { it.isEven() })

Wynik:

HELLO!
false
2

Rozszerzenia działają także na własnych klasach, a właściwości rozszerzające dodają właściwości obliczane. Rozszerzenie nie może dodawać przechowywanego stanu i ma dostęp tylko do publicznych składowych swojego odbiorcy:

class Temperature(val celsius: Double)

val Temperature.fahrenheit: Double
    get() = celsius * 9 / 5 + 32

fun Temperature.describe() = "$celsius C is $fahrenheit F"

Wewnątrz main:

println(Temperature(100.0).describe())

Wynik:

100.0 C is 212.0 F

Rozszerzenia są rozstrzygane statycznie: typ zadeklarowany wyrażenia wybiera rozszerzenie podczas kompilacji programu, a nie klasa obiektu. To główna różnica w porównaniu z przesłoniętą składową:

open class Shape {
    open fun member() = "shape member"
}
class Circle : Shape() {
    override fun member() = "circle member"
}

fun Shape.ext() = "shape extension"
fun Circle.ext() = "circle extension"

Wewnątrz main:

val s: Shape = Circle()
println(s.member())
println(s.ext())

Wynik:

circle member
shape extension

Jeśli klasa ma już składową o takim samym podpisie, składowa zawsze wygrywa. Używaj składowych w przypadku zachowań, które należą do typu i mogą być nadpisywane; używaj rozszerzeń w przypadku pomocniczych funkcji dodawanych z zewnątrz, takich jak formatowanie dla klasy, której nie jesteś właścicielem:

class Robot {
    fun greet() = "member greet"
}

fun Robot.greet() = "extension greet"
fun Robot.wave() = "extension wave"

Wewnątrz main:

val r = Robot()
println(r.greet())
println(r.wave())

Wynik:

member greet
extension wave
challenge icon

Wyzwanie

Łatwy

Money(cents) jest dostarczone w pliku Money.kt. Napisz dla niego rozszerzenia w pliku MoneyExtensions.kt: właściwości rozszerzające Int.dollars i Int.cents, które zamieniają liczbę na Money (12.dollars to 1200 centów), Money.format(), które zwraca $12.50 (lub -$3.05 dla kwot ujemnych), List<Money>.total(), które zwraca sumę jako Money, oraz Money.split(parts), które dzieli kwotę na parts części różniących się o najwyżej jeden cent, przy czym większe części są na początku.

Dostarczony kod odczytuje wiersze 12 dollars lub 50 cents oraz ostatni wiersz zawierający liczbę części. Wyświetla każdą kwotę, total: $12.50 i split 3: $4.17 $4.17 $4.16.

Twój kod umieść w plikach MoneyExtensions.kt i Money.kt. Plik Main.kt zawiera dostarczony kod wejścia/wyjścia i nie można go edytować.

Spróbuj swoich sił

fun main() {
    // Dostarczony kod wejścia/wyjścia: pozostaw go bez zmian
    val input = generateSequence(::readLine).toList()
    val amounts = input.dropLast(1).map { line ->
        val (n, unit) = line.split(" ")
        if (unit == "dollars") n.toInt().dollars else n.toInt().cents
    }
    for (m in amounts) println(m.format())
    val total = amounts.total()
    println("total: ${total.format()}")
    val parts = input.last().toInt()
    println("split $parts: " + total.split(parts).joinToString(" ") { it.format() })
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Edytor online Kotlin