Kotlin - Generics (Typy generyczne) cz.1

Typy generyczne pozwalają stworzyć bardziej uniwersalny kod oraz uniknąc duplikacji klas o tych samych elementach konstrukcyjnych. Zapraszam do czytania.

Wstęp

W oficjalnej dokumentacji języka Kotlin na temat generyków dosyć szybko przechodzą do tłumaczenia zawiłości takich jak wildcards czy ograniczenia.

Ja w dwóch artykułach rozbiję treść na podstawę oraz wytłumaczenie owych zawiłości w Kotlin'ie.

Na początku zobaczmy jak wygląda definicja podstawowych elementów takich jak funkcje i klasy.

Generyczna klasa Shop przyjmuje dowolną klasę jako parametr wejściowy i wypisuje jej nazwę. Jako, że typ T jest rozszerzony przez Any to mogłaby się tutaj również znaleźć klasa zupełnie nie związana ze sklepami.

Dzięki typom generycznym kompilator wie jakich klas używamy przez co w lini 13 ominąłem Operator diamentowy.

W funkcjach zaraz po słowie kluczowym fun deklarujemy typ parametru.

Variance

W przykładzie wyżej podkreśliłem, że do klasy Shop możemy podać klasę dowolnego typu co stwarza pewien problem. My chcemy aby klasa Shop przyjmowała jedynie obiekty dziedziczące po Company.

Zanim jednak pokażę na przykładzie jak to może wyglądać trzeba rozwiać tajmenicę wildcards.

W javie typy generyczne są niezmienne to znaczy, iż np. w List od String nie jest podtypem List od Object.

W naszym języku rozwiążemy to za pomocą ograniczenia zestawu klas T: Company.

Tak wygląda interfejs Company oraz klasy, które go implementują.

A tak wygląda przykład wykorzystania.

Nie dość, że teraz akceptowane klasy na pewno będą obiektami dziedziczącymi po Company to dodatkowo możemy wywołać funkcję getName() w klasie generycznej Shop. Znacznie zabezpiecza to oraz upraszcza kod.

Wildcards

Autorzy języka mocno zwracają uwagę na problem dzikich kart w Javie. Fantastycznie zostało to opisane na stronie samouczekprogramisty.pl tutaj. Gorąco zachęcam do sprawdzenia.

Ja spróbuję opisać jaka jest różnica pomiędzy producentem, a konsumentem w krótkich żołnierskich słowach.

Od producenta ? extends E odczytujemy obiekty.

Do konsumenta ? super E możemy zapisywać obiekty

Out

Typ parametru T out w klasie lub interfejsie generyczny oznacza, że typem zwracanym przez funkcje będzie T.

Można nazwać go producentem bo interesuje nas ten typ, który z niego wyciągniemy.

Dzięki takiemu użyciu słowa out możemy przechować str w item i korzystać z metody nextT(). Adnotacja out pozwala tylko na wyjściowy parametr T.

In

Odwrotnie ma się sytuacja z in. W tym przypadku funkcje konsumują (przyjmują) parametry generyczne.

Przykład z dokumentacji Kotlin'a doskonale tłumaczy jak zachowuje się in. Jako, że Double dziedziczy po Number to możemy użyć compareTo()


Dziękuję Ci za przeczytanie tego materiału. Typy generyczne to nie jest łatwy temat i wielokrotnie prowadzą do bólu głowy. W części drugiej postaram się opisać resztę funkcjonalności w Kotlin'ie odnośnie generyków.

shop
Otwórz Sklep Play

Zachęcam cię do odwiedzenia mojej strony na Google Play store i sprawdzenia wszystkich moich aplikacji.