article banner

Twój pierwszy program w Kotlinie

To jest rozdział z książki Kotlin Essentials.

Pierwszym krokiem w naszej przygodzie z Kotlinem jest napisanie minimalnego programu w tym języku. Tak, słynny program "Hello, World!". Oto jak wygląda on w Kotlinie:

fun main() { println("Hello, World") }

Niewiele potrzeba, prawda? Nie potrzebujemy klas (jak w Javie), żadnych obiektów (jak console w JavaScripcie) ani warunków (jak w Pythonie). Potrzebujemy funkcji main oraz wywołania funkcji println z dowolnym tekstem0.

To jest najbardziej popularny (choć nie jedyny) wariant funkcji "main". Jeśli potrzebujemy argumentów, możemy dołączyć parametr typu Array<String>:

fun main(args: Array<String>) { println("Hello, World") }

Istnieją także inne formy funkcji main:

fun main(vararg args: String) { println("Hello, World") }
class Test { companion object { @JvmStatic fun main(args: Array<String>) { println("Hello, World") } } }
suspend fun main() { println("Hello, World") }

Chociaż wszystkie te formy są poprawne, skupmy się na prostym main, gdyż będzie on najbardziej użyteczny. Użyję go niemal w każdym przykładzie w tej książce. Te przykłady w większości są całymi programami, które możesz uruchomić, jeśli tylko skopiujesz i wkleisz je do IDE lub do Kotlin Playground2.

fun main() { println("Hello, World") }

Wszystko, co musisz zrobić, aby uruchomić funkcję main w IntelliJ (najpopularniejszym IDE Kotlina), to kliknąć zielony trójkąt, który pojawia się po lewej stronie funkcji main (znany jako "gutter icon").

Szablony dynamiczne

Jeśli zdecydujesz się przetestować lub przećwiczyć materiał z tej książki3, prawdopodobnie często będziesz pisać funkcję main. Na pomoc przychodzą nam szablony dynamiczne (live templates). Jest to funkcjonalność IntelliJ, która sugeruje użycie szablonu, gdy zaczynasz wpisywać jego nazwę w odpowiednim kontekście. Czyli jeśli zaczniesz wpisywać "main" lub "maina" (dla main z argumentami) w pliku Kotlin, zostanie Ci pokazana sugestia, która oferuje całą funkcję main.

Na większości moich warsztatów używałem tego szablonu setki razy. Kiedy tylko chcę pokazać coś nowego z kodowaniem na żywo, otwieram plik "Playground.kt", zaznaczam całą jego zawartość (Ctrl/command + A), wpisuję "main", potwierdzam szablon dynamiczny klawiszem Enter i mam idealną przestrzeń do pokazania, jak coś działa.

Polecam, abyś przetestował to teraz. Otwórz dowolny projekt Kotlin (najlepiej, jeśli masz dedykowany projekt do zabawy z Kotlinem), utwórz nowy plik (możesz go nazwać "Test" lub "Playground") i dodaj funkcję main, posługując się szablonem dynamicznym "maina". Użyj funkcji print z dowolnym tekstem i uruchom kod przyciskiem "Uruchom".

Co kryje się pod maską na JVM?

Najważniejszym targetem Kotlina jest JVM (Java Virtual Machine). W JVM każdy element musi znajdować się w klasie. Możesz zatem zastanawiać się, jak to możliwe, że nasza funkcja "main" może być uruchomiona w JVM, skoro nie jest w żadnej klasie. Spróbujmy to wyjaśnić. Po drodze nauczymy się, jak sprawdzić, jak nasz kod w Kotlinie wyglądałby, gdyby był napisany w Javie. Ta możliwość jest niesamowitą pomocą przy nauce Kotlina.

Zacznijmy od otwarcia lub uruchomienia projektu Kotlin w IntelliJ lub Android Studio. Stwórz nowy plik Kotlin o nazwie "Playground". W środku tego pliku użyj szablonu dynamicznego "maina", aby utworzyć główną funkcję z argumentami i dodać println("Hello, World") w środku.

fun main(args: Array<String>) { println("Hello, World") }

Teraz wybierz z zakładek Tools > Kotlin > Show Kotlin Bytecode.

Po prawej stronie powinno otworzyć się nowe narzędzie. "Show Kotlin Bytecode" pokazuje bytecode JVM generowany z tego pliku.

To świetne miejsce dla każdego, kto lubi czytać bajtkod JVM. Ponieważ nie wszyscy są jak Jake Wharton, w związku z tym większość z nas może uznać przycisk "Decompile" za przydatny. To, co robi, jest dość zabawne. Skompilowaliśmy nasz kod w Kotlinie do bytecode'u JVM, a ten przycisk pozwoli nam go wyświetlić po zdekompilowaniu do Javy. W rezultacie możemy zobaczyć, jak wyglądałby nasz kod, gdyby był napisany w Javie5.

Ten kod ujawnia, że nasza funkcja main na JVM staje się statyczną funkcją wewnątrz klasy o nazwie PlaygroundKt. Skąd pochodzi ta nazwa? Spróbuj zgadnąć. Tak, domyślnie jest to nazwa pliku z sufiksem "Kt". To samo dzieje się ze wszystkimi innymi funkcjami i właściwościami zdefiniowanymi poza klasami na JVM. Jeśli chcielibyśmy wywołać naszą funkcję main w Javie, możemy wywołać PlaygroundKt.main({}).

Nazwę PlaygroundKt można zmienić, dodając adnotację @file:JvmName("NewName") w pierwszej linii pliku źródłowego6. Nie wpłynie to na użycie tych elementów z języka Kotlin, ale zmienia nazwę klasy, gdy używana jest w innych językach JVM. Po tej zmianie moglibyśmy wywołać funkcję main w Javie jako NewName.main({}).

Jeśli masz doświadczenie z Javy, zapamiętaj to narzędzie, ponieważ może pomóc Ci zrozumieć:

  • Jak działa kod Kotlin na niskim poziomie.
  • Jak działa konkretna funkcja Kotlina "pod maską".
  • Jak korzystać w Javie z elementu napisanego w języku Kotlin.

Istnieją propozycje stworzenia podobnego narzędzia, aby pokazywać kod JavaScript generowany z kodu Kotlin, gdy naszym targetem jest Kotlin/JS. Jednak w momencie pisania tej książki najlepszym, co możesz zrobić, jest samodzielne otwieranie wygenerowanych plików.

Pakiety i importowanie

Kiedy nasz projekt ma więcej niż jeden plik, potrzebujemy pakietów, aby utrzymywać jakiś porządek. Pakiety są sposobem grupowania plików i unikania konfliktów nazw. Plik może określić pakiet na początku pliku za pomocą słowa kluczowego package.

package com.marcinmoskala.domain.model class User(val name: String)

Jeśli nie określimy pakietu, plik znajdzie się w pakiecie domyślnym. W prawdziwych projektach zaleca się, aby ścieżka pakietu była taka sama jak ścieżka katalogu w naszych plikach źródłowych. Pakiet może również zawierać domenę firmy w odwrotnej kolejności, np. com.marcinmoskala. Nazwy pakietów piszemy małymi literami.

Jeśli chcemy użyć funkcji lub klasy z innego pakietu, musimy go zaimportować. Importy są deklarowane po deklaracji pakietu i przed deklaracjami elementów7 pliku. Najpierw określają nazwę pakietu, a następnie nazwę importowanego elementu. Możemy również użyć znaku * do zaimportowania wszystkich elementów.

package com.marcinmoskala.domain import com.marcinmoskala.domain.model.User // albo import com.marcinmoskala.domain.model.* fun useUser() { val user = User("Marcin") // ... }

Najważniejsze elementy biblioteki standardowej Kotlina oraz Javy są importowane domyślnie. Na przykład możemy użyć funkcji println bez importowania jej.

Programiści Kotlina rzadko myślą o importach, ponieważ IntelliJ zarządza nimi automatycznie. Kiedy użyjesz elementu za pomocą sugestii IntelliJ, automatycznie doda on odpowiedni import. Jeśli używasz elementu, który nie jest zaimportowany, IntelliJ zaproponuje jego zaimportowanie. Jeśli chcesz usunąć nieużywane importy, możesz użyć akcji "Optimize Imports" (Ctrl/command + Alt + O). To też jest powodem, dla którego zdecydowałem się nie pokazywać importów w większości przykładów w tej książce.

Podsumowanie

Nauczyliśmy się korzystać z funkcji main i jak łatwo ją stworzyć przy pomocy szablonów dynamicznych. Dowiedzieliśmy się też jak sprawdzić, jak nasz kod Kotlin wyglądałby, gdyby był napisany w Javie. To chyba niezły początek naszej przygody, więc bez zbędnych ceregieli chodźmy dalej.

0:

Funkcja println jest niejawnie importowana z pakietu biblioteki standardowej kotlin.io.

2:

Niektóre rozdziały tej książki można również znaleźć online na stronie Kt. Academy. Przykłady w nich zawarte można uruchomić i modyfikować dzięki funkcji Kotlin Playground.

3:

Cieszę się, gdy ludzie próbują podważyć to, czego nauczałem. Bądź sceptyczny i weryfikuj to, czego się nauczyłeś; to świetny sposób na naukę czegoś nowego i pogłębienie zrozumienia.

5:

To nie zawsze działa, ponieważ dekompilator nie jest doskonały, ale i tak jest bardzo pomocny.

6:

Więcej na ten temat w książce Zaawansowany Kotlin, rozdział Interoperacyjność Kotlin i Java.

7:

Poprzez elementy w kontekście Kotlina mamy na myśli klasy, funkcje, właściwości, obiekty, interfejsy, enumy, itp. Wszystkie typy elementów omówimy w kolejnych rozdziałach.