programowanieProgramista mobilny Kotlin

Czym są funkcje rozszerzające (extension functions) w Kotlinie i jak je poprawnie używać? Opisz pułapki ich stosowania i podaj przykład kodu.

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź.

Funkcje rozszerzające/extension functions — to mechanizm, który pozwala dodawać nowe funkcje do istniejących klas bez potrzeby dziedziczenia lub modyfikowania samej klasy.

Na przykład, dla klasy String, dodajmy funkcję, która odwraca ciąg:

fun String.reverse(): String { return this.reversed() } println("abc".reverse()) // "cba"

Rozszerzenia w rzeczywistości nie modyfikują klasy, a jedynie są syntaktycznym cukrem: są kompilowane jako metody statyczne, które przyjmują instancję obiektu jako pierwszy parametr.

Zalety: zwięzłość, czytelność, rozszerzalność kodu. Dobrze sprawdzają się jako funkcje pomocnicze dla kolekcji, ciągów itd.

Pułapki:

  • Nie mogą nadpisywać/zastępować metod klasy;
  • Nie mają dostępu do prywatnych członów klasy;
  • W przypadku konfliktu nazw wygrywa metoda instancji, a nie rozszerzenia;
  • Extension property działa tylko z getter/setter, nie z polami;

Pytanie z podstępnym dnem.

Czy można za pomocą funkcji rozszerzających dodać nową zmienną (property), która przechowuje stan, do klasy?

Odpowiedź: Nie. Extension property to zawsze właściwość obliczana (getter/setter), nie pole. Nie mogą przechowywać stanu — tylko obliczać na bieżąco.

val String.secondChar: Char get() = this[1] // Tylko obliczenie, nie przechowywanie!

Przykłady rzeczywistych błędów z powodu braku znajomości szczegółów tematu.


Historia

W projekcie weryfikacji danych programista dodał extension property do modelowej klasy, jakby przechowywała wartość, ale później zauważył, że wartość zawsze jest obliczana, a nie zapamiętywana, co spowodowało, że logika działała niepoprawnie przy wielokrotnych wywołaniach.


Historia

W dużej aplikacji rozszerzenia nazwano tak samo, jak metody klasy, co doprowadziło do zamieszania: metody klasy zawsze miały priorytet, a rozszerzenia nie były wywoływane — zmarnowano dzień na debugowanie "niewidocznego" kodu.


Historia

W jednej z bibliotek rozszerzenia były używane dla prywatnych pól klasy, ale później okazało się, że nie mają dostępu do prywatnych pól, co zmusiło do refaktoryzacji architektury modeli.