Kotlin Bootcamp for Programmers 3: Funkcje

Te warsztaty są częścią kursu Kotlin Bootcamp for Programmers. Najwięcej korzyści przyniesie Ci ukończenie wszystkich ćwiczeń w kolejności. W zależności od swojej wiedzy możesz pominąć niektóre sekcje. Ten kurs jest przeznaczony dla programistów, którzy znają język obiektowy i chcą nauczyć się Kotlin.

Wprowadzenie

W tym laboratorium kodowania utworzysz program w Kotlinie i dowiesz się więcej o funkcjach w tym języku, w tym o wartościach domyślnych parametrów, filtrach, wyrażeniach lambda i funkcjach kompaktowych.

Lekcje w tym kursie nie są powiązane z jedną przykładową aplikacją. Zostały zaprojektowane tak, aby poszerzać Twoją wiedzę, ale jednocześnie były od siebie częściowo niezależne. Dzięki temu możesz przeglądać sekcje, które już znasz. Aby je ze sobą powiązać, w wielu przykładach użyto motywu akwarium. Jeśli chcesz poznać pełną historię akwarium, zapoznaj się z kursem Kotlin Bootcamp for Programmers na platformie Udacity.

Co warto wiedzieć

  • Podstawy nowoczesnego, obiektowego, statycznie typowanego języka programowania
  • umiejętność programowania z użyciem klas, metod i obsługi wyjątków w co najmniej jednym języku;
  • Jak korzystać z REPL (Read-Eval-Print Loop) w Kotlinie w IntelliJ IDEA
  • Podstawy języka Kotlin, w tym typy, operatory i pętle

Te warsztaty są przeznaczone dla programistów, którzy znają język obiektowy i chcą dowiedzieć się więcej o Kotlinie.

Czego się nauczysz

  • Jak utworzyć program z funkcją main() i argumentami w IntelliJ IDEA
  • Jak używać wartości domyślnych i funkcji kompaktowych
  • Jak stosować filtry do list
  • Tworzenie podstawowych funkcji lambda i funkcji wyższego rzędu

Jakie zadania wykonasz

  • Pracuj z REPL, aby wypróbować kod.
  • Twórz podstawowe programy w Kotlinie za pomocą IntelliJ IDEA.

W tym zadaniu utworzysz program w języku Kotlin i dowiesz się więcej o funkcji main() oraz o tym, jak przekazywać argumenty do programu z wiersza poleceń.

Możesz pamiętać funkcję printHello(), którą wpisaliśmy w REPL w poprzednim laboratorium:

fun printHello() {
    println ("Hello World")
}

printHello()
⇒ Hello World

Funkcje definiuje się za pomocą słowa kluczowego fun, po którym następuje nazwa funkcji. Podobnie jak w przypadku innych języków programowania nawiasy () służą do określania argumentów funkcji, jeśli takie istnieją. Nawiasy klamrowe {} otaczają kod funkcji. Ta funkcja nie zwraca żadnej wartości.

Krok 1. Utwórz plik Kotlin

  1. Otwórz IntelliJ IDEA.
  2. Panel Projekt po lewej stronie w IntelliJ IDEA zawiera listę plików i folderów projektu. Znajdź folder src i kliknij go prawym przyciskiem myszy. (Projekt Hello Kotlin powinien być już dostępny z poprzednich zajęć).
  3. Wybierz New > Kotlin File / Class (Nowy > Plik/klasa Kotlin).
  4. W polu Rodzaj wybierz Plik i nadaj plikowi nazwę Hello.
  5. Kliknij OK.

W folderze src znajduje się teraz plik o nazwie Hello.kt.

Krok 2. Dodaj kod i uruchom program

  1. Podobnie jak w przypadku innych języków funkcja main() w języku Kotlin określa punkt wejścia do wykonania. Wszystkie argumenty wiersza poleceń są przekazywane jako tablica ciągów znaków.

    Wpisz lub wklej ten kod do pliku Hello.kt :
fun main(args: Array<String>) {
    println("Hello, world!")
}

Podobnie jak poprzednia funkcja printHello(), ta funkcja nie zawiera instrukcji return. Każda funkcja w Kotlinie zwraca jakąś wartość, nawet jeśli nie jest to wyraźnie określone. Funkcja taka jak main() zwraca typ kotlin.Unit, co w języku Kotlin oznacza brak wartości.

  1. Aby uruchomić program, kliknij zielony trójkąt po lewej stronie funkcji main(). W menu wybierz Uruchom „HelloKt”.
  2. IntelliJ IDEA skompiluje program i go uruchomi. Wyniki pojawią się w panelu logów u dołu, jak pokazano poniżej.

Krok 3. Przekazywanie argumentów do funkcji main()

Ponieważ program jest uruchamiany w środowisku IntelliJ IDEA, a nie w wierszu poleceń, argumenty programu musisz podać w nieco inny sposób.

  1. Kliknij Uruchom > Edytuj konfiguracje. Otworzy się okno Run/Debug Configurations (Konfiguracje uruchamiania/debugowania).
  2. Wpisz Kotlin! w polu Argumenty programu.
  3. Kliknij OK.

Krok 4. Zmień kod, aby używać szablonu ciągu znaków

Szablon ciągu znaków wstawia zmienną lub wyrażenie do ciągu znaków i $ określa, że część ciągu znaków będzie zmienną lub wyrażeniem. Klamry {} otaczają wyrażenie, jeśli występuje.

  1. W pliku Hello.kt zmień wiadomość powitalną, aby zamiast "world" używać pierwszego argumentu przekazanego do programu, czyli args[0].
fun main(args: Array<String>) {
    println("Hello, ${args[0]}")
}
  1. Uruchom program. Dane wyjściowe będą zawierać określony argument.
⇒ Hello, Kotlin!

W tym ćwiczeniu dowiesz się, dlaczego prawie wszystko w Kotlinie ma wartość i dlaczego jest to przydatne.

W niektórych innych językach występują instrukcje, czyli wiersze kodu, które nie mają wartości. W języku Kotlin prawie wszystko jest wyrażeniem i ma wartość, nawet jeśli jest to kotlin.Unit.

  1. W pliku Hello.kt napisz kod w funkcji main(), aby przypisać wartość println() do zmiennej o nazwie isUnit i wydrukować ją. (Funkcja println() nie zwraca wartości, więc zwraca kotlin.Unit).
// Will assign kotlin.Unit
val isUnit = println("This is an expression")
println(isUnit)
  1. Uruchom program. Pierwszy znak println() drukuje ciąg znaków "This is an expression". Druga instrukcja println() drukuje wartość pierwszej instrukcji println(), czyli kotlin.Unit.
⇒ This is an expression
kotlin.Unit
  1. Zadeklaruj zmienną val o nazwie temperature i zainicjuj ją wartością 10.
  2. Zadeklaruj kolejną zmienną val o nazwie isHot i przypisz do niej wartość zwracaną instrukcji if/else, jak pokazano w poniższym kodzie.isHot Ponieważ jest to wyrażenie, możesz od razu użyć wartości wyrażenia if.
val temperature = 10
val isHot = if (temperature > 50) true else false
println(isHot)
⇒ false
  1. Użyj wartości wyrażenia w szablonie ciągu. Dodaj kod, który sprawdzi temperaturę, aby określić, czy ryba jest bezpieczna, czy zbyt ciepła, a następnie uruchom program.
val temperature = 10
val message = "The water temperature is ${ if (temperature > 50) "too warm" else "OK" }."
println(message)
⇒ The water temperature is OK.

W tym ćwiczeniu dowiesz się więcej o funkcjach w Kotlinie i o bardzo przydatnym wyrażeniu warunkowym when.

Krok 1. Utwórz kilka funkcji

W tym kroku wykorzystasz zdobytą wiedzę i utworzysz funkcje z różnymi typami. Możesz zastąpić zawartość pliku Hello.kt tym nowym kodem.

  1. Napisz funkcję o nazwie feedTheFish(), która wywołuje funkcję randomDay(), aby uzyskać losowy dzień tygodnia. Użyj szablonu ciągu znaków, aby wydrukować food, które ryba zje tego dnia. Na razie ryby jedzą codziennie to samo.
fun feedTheFish() {
    val day = randomDay()
    val food = "pellets"
    println ("Today is $day and the fish eat $food")
}

fun main(args: Array<String>) {
    feedTheFish()
}
  1. Napisz funkcję randomDay(), która wybiera losowy dzień z tablicy i zwraca go.

Funkcja nextInt() przyjmuje limit liczby całkowitej, który ogranicza liczbę od Random() do 0 przez 6, aby pasowała do tablicy week.

fun randomDay() : String {
    val week = arrayOf ("Monday", "Tuesday", "Wednesday", "Thursday",
            "Friday", "Saturday", "Sunday")
    return week[Random().nextInt(week.size)]
}
  1. Funkcje Random()nextInt() są zdefiniowane w java.util.*. U góry pliku dodaj potrzebny import:
import java.util.*    // required import
  1. Uruchom program i sprawdź dane wyjściowe.
⇒ Today is Tuesday and the fish eat pellets

Krok 2. Użyj wyrażenia „when”

Rozszerzając ten przykład, zmień kod tak, aby wybierał różne produkty spożywcze w różne dni za pomocą wyrażenia when. Instrukcja when jest podobna do instrukcji switch w innych językach programowania, ale when automatycznie przerywa działanie na końcu każdej gałęzi. Dzięki temu masz też pewność, że kod obejmuje wszystkie gałęzie, jeśli sprawdzasz wyliczenie.

  1. W pliku Hello.kt dodaj funkcję o nazwie fishFood(), która przyjmuje dzień jako String i zwraca pokarm dla ryb na dany dzień jako String. Użyj when(), aby każdego dnia ryba otrzymywała określony pokarm. Uruchom program kilka razy, aby zobaczyć różne wyniki.
fun fishFood (day : String) : String {
    var food = ""
    when (day) {
        "Monday" -> food = "flakes"
        "Tuesday" -> food = "pellets"
        "Wednesday" -> food = "redworms"
        "Thursday" -> food = "granules"
        "Friday" -> food = "mosquitoes"
        "Saturday" -> food = "lettuce"
        "Sunday" -> food = "plankton"
    }
    return food
}

fun feedTheFish() {
    val day = randomDay()
    val food = fishFood(day)

    println ("Today is $day and the fish eat $food")
}
⇒ Today is Thursday and the fish eat granules
  1. Dodaj gałąź domyślną do wyrażenia when za pomocą else. Aby sprawdzić, czy w programie czasami jest używana wartość domyślna, usuń gałęzie TuesdaySaturday.

    Gałąź domyślna zapewnia, że zmienna food otrzymuje wartość przed zwróceniem, więc nie trzeba jej już inicjować. Ponieważ kod przypisuje ciąg znaków do zmiennej food tylko raz, możesz zadeklarować food za pomocą val zamiast var.
fun fishFood (day : String) : String {
    val food : String
    when (day) {
        "Monday" -> food = "flakes"
        "Wednesday" -> food = "redworms"
        "Thursday" -> food = "granules"
        "Friday" -> food = "mosquitoes"
        "Sunday" -> food = "plankton"
        else -> food = "nothing"
    }
    return food
}
  1. Każde wyrażenie ma wartość, więc ten kod można nieco skrócić. Zwróć bezpośrednio wartość wyrażenia when i usuń zmienną food. Wartością wyrażenia when jest wartość ostatniego wyrażenia w gałęzi, która spełniła warunek.
fun fishFood (day : String) : String {
    return when (day) {
        "Monday" -> "flakes"
        "Wednesday" -> "redworms"
        "Thursday" -> "granules"
        "Friday" -> "mosquitoes"
        "Sunday" -> "plankton"
        else -> "nothing"
    }
}

Ostateczna wersja programu powinna wyglądać podobnie do kodu poniżej.

import java.util.*    // required import

fun randomDay() : String {
    val week = arrayOf ("Monday", "Tuesday", "Wednesday", "Thursday",
        "Friday", "Saturday", "Sunday")
    return week[Random().nextInt(week.size)]
}

fun fishFood (day : String) : String {
    return when (day) {
        "Monday" -> "flakes"
        "Wednesday" -> "redworms"
        "Thursday" -> "granules"
        "Friday" -> "mosquitoes"
        "Sunday" -> "plankton"
        else -> "nothing"
    }
}

fun feedTheFish() {
    val day = randomDay()
    val food = fishFood(day)
    println ("Today is $day and the fish eat $food")
}

fun main(args: Array<String>) {
    feedTheFish()
}

W tym ćwiczeniu dowiesz się więcej o wartościach domyślnych funkcji i metod. Dowiesz się też o funkcjach kompaktowych, które mogą sprawić, że Twój kod będzie bardziej zwięzły i czytelny, a także zmniejszyć liczbę ścieżek kodu do testowania. Funkcje zwarte są też nazywane funkcjami z jednym wyrażeniem.

Krok 1. Utwórz wartość domyślną parametru

W Kotlinie argumenty można przekazywać według nazwy parametru. Możesz też określić wartości domyślne parametrów: jeśli wywołujący nie poda argumentu, używana jest wartość domyślna. Później, gdy będziesz pisać metody (funkcje składowe), będziesz mieć możliwość uniknięcia pisania wielu wersji przeciążonych tej samej metody.

  1. W pliku Hello.kt napisz funkcję swim() z parametrem String o nazwie speed, która wyświetla prędkość ryby. Parametr speed ma wartość domyślną "fast".
fun swim(speed: String = "fast") {
   println("swimming $speed")
}
  1. Z poziomu funkcji main() wywołaj funkcję swim() na 3 sposoby. Najpierw wywołaj funkcję, używając wartości domyślnej. Następnie wywołaj funkcję i przekaż parametr speed bez nazwy, a potem wywołaj funkcję, podając nazwę parametru speed.
swim()   // uses default speed
swim("slow")   // positional argument
swim(speed="turtle-like")   // named parameter
⇒ swimming fast
swimming slow
swimming turtle-like

Krok 2. Dodaj wymagane parametry

Jeśli dla parametru nie określono wartości domyślnej, odpowiedni argument musi być zawsze przekazywany.

  1. W pliku Hello.kt napisz funkcję shouldChangeWater(), która przyjmuje 3 parametry: day, temperature i poziom dirty. Funkcja zwraca true, jeśli należy wymienić wodę, co ma miejsce w niedzielę, gdy temperatura jest zbyt wysoka lub gdy woda jest zbyt brudna. Dzień tygodnia jest wymagany, ale domyślna temperatura to 22, a domyślny poziom zabrudzenia to 20.

    Użyj wyrażenia when bez argumentu, które w języku Kotlin działa jak seria sprawdzeń if/else if.
fun shouldChangeWater (day: String, temperature: Int = 22, dirty: Int = 20): Boolean {
    return when {
        temperature > 30 -> true
        dirty > 30 -> true
        day == "Sunday" ->  true
        else -> false
    }
}
  1. Zadzwoń pod numer shouldChangeWater() z numeru feedTheFish() i podaj dzień. Parametr day nie ma wartości domyślnej, więc musisz podać argument. Pozostałe 2 parametry funkcji shouldChangeWater() mają wartości domyślne, więc nie musisz przekazywać do nich argumentów.
fun feedTheFish() {
    val day = randomDay()
    val food = fishFood(day)
    println ("Today is $day and the fish eat $food")
    println("Change water: ${shouldChangeWater(day)}")
}
=> Today is Thursday and the fish eat granules
Change water: false

Krok 3. Twórz kompaktowe funkcje

Wyrażenie when napisane w poprzednim kroku zawiera dużo logiki w niewielkiej ilości kodu. Jeśli chcesz to nieco rozwinąć lub jeśli warunki do sprawdzenia są bardziej skomplikowane, możesz użyć dobrze nazwanych zmiennych lokalnych. W Kotlinie robi się to jednak za pomocą funkcji kompaktowych.

Funkcje zwarte, czyli funkcje jedno wyrażeniowe, to powszechny wzorzec w języku Kotlin. Jeśli funkcja zwraca wyniki pojedynczego wyrażenia, możesz określić treść funkcji po symbolu =, pominąć nawiasy klamrowe {} i pominąć return.

  1. W pliku Hello.kt dodaj kompaktowe funkcje, aby przetestować warunki.
fun isTooHot(temperature: Int) = temperature > 30

fun isDirty(dirty: Int) = dirty > 30

fun isSunday(day: String) = day == "Sunday"
  1. Zmień funkcję shouldChangeWater() tak, aby wywoływała nowe funkcje.
fun shouldChangeWater (day: String, temperature: Int = 22, dirty: Int = 20): Boolean {
    return when {
        isTooHot(temperature) -> true
        isDirty(dirty) -> true
        isSunday(day) -> true
        else  -> false
    }
}
  1. Uruchom program. Dane wyjściowe z urządzenia println() z urządzeniem shouldChangeWater() powinny być takie same jak przed przejściem na funkcje kompaktowe.

Wartości domyślne

Wartość domyślna parametru nie musi być wartością. Może to być inna funkcja, jak pokazano w tym częściowym przykładzie:

fun shouldChangeWater (day: String, temperature: Int = 22, dirty: Int = getDirtySensorReading()): Boolean {
    ...

W tym zadaniu dowiesz się nieco więcej o filtrach w Kotlinie. Filtry to przydatny sposób na uzyskanie części listy na podstawie określonego warunku.

Krok 1. Utwórz filtr

  1. W pliku Hello.kt zdefiniuj listę dekoracji akwariowych na najwyższym poziomie za pomocą listOf(). Możesz zastąpić zawartość pliku Hello.kt.
val decorations = listOf ("rock", "pagoda", "plastic plant", "alligator", "flowerpot")
  1. Utwórz nową funkcję main() z wierszem, który będzie wyświetlać tylko dekoracje zaczynające się na literę „p”. Kod warunku filtra znajduje się w nawiasach klamrowych {}, a it odnosi się do każdego elementu w pętli filtra. Jeśli wyrażenie zwraca wartość true, produkt jest uwzględniany.
fun main() {
    println( decorations.filter {it[0] == 'p'})
}
  1. Uruchom program. W oknie Uruchom zobaczysz te dane wyjściowe:
⇒ [pagoda, plastic plant]

Krok 2. Porównaj filtry eager i lazy

Jeśli znasz filtry w innych językach, możesz się zastanawiać, czy filtry w Kotlinie są gorliwe czy leniwe. Czy lista wyników jest tworzona od razu, czy dopiero po otwarciu listy? W Kotlinie możesz to zrobić w dowolny sposób. Domyślnie filter jest wykonywane od razu i za każdym razem, gdy używasz filtra, tworzona jest lista.

Aby filtr był leniwy, możesz użyć Sequence, czyli kolekcji, która może przeglądać tylko jeden element naraz, zaczynając od początku i przechodząc do końca. Na szczęście jest to dokładnie ten interfejs API, którego potrzebuje filtr leniwy.

  1. W pliku Hello.kt zmień kod tak, aby przypisywał przefiltrowaną listę do zmiennej o nazwie eager, a następnie ją wyświetlał.
fun main() {
    val decorations = listOf ("rock", "pagoda", "plastic plant", "alligator", "flowerpot")

    // eager, creates a new list
    val eager = decorations.filter { it [0] == 'p' }
    println("eager: " + eager)
  1. Pod tym kodem oceń filtr za pomocą symbolu Sequence z symbolem asSequence(). Przypisz sekwencję do zmiennej o nazwie filtered i ją wydrukuj.
   // lazy, will wait until asked to evaluate
    val filtered = decorations.asSequence().filter { it[0] == 'p' }
    println("filtered: " + filtered)

Jeśli zwrócisz wyniki filtrowania jako Sequence, zmienna filtered nie będzie zawierać nowej listy, ale Sequence elementów listy i informacje o filtrze, który należy zastosować do tych elementów. Za każdym razem, gdy uzyskujesz dostęp do elementów Sequence, filtr jest stosowany, a wynik jest zwracany.

  1. Wymuś obliczenie sekwencji, przekształcając ją w ListtoList(). Wydrukuj wynik.
    // force evaluation of the lazy list
    val newList = filtered.toList()
    println("new list: " + newList)
  1. Uruchom program i obserwuj dane wyjściowe.
⇒ eager: [pagoda, plastic plant]
filtered: kotlin.sequences.FilteringSequence@386cc1c4
new list: [pagoda, plastic plant]

Aby zobaczyć, co się dzieje z funkcją Sequence i leniwą oceną, użyj funkcji map(). Funkcja map() wykonuje proste przekształcenie każdego elementu w sekwencji.

  1. Na tej samej liście decorations co powyżej wykonaj transformację za pomocą funkcji map(), która nic nie robi i po prostu zwraca przekazany element. Dodaj println(), aby pokazywać za każdym razem, gdy uzyskiwany jest dostęp do elementu, i przypisz sekwencję do zmiennej o nazwie lazyMap.
    val lazyMap = decorations.asSequence().map {
        println("access: $it")
        it
    }
  1. Wydrukuj lazyMap, wydrukuj pierwszy element lazyMap za pomocą first() i wydrukuj lazyMap przekonwertowane na List.
    println("lazy: $lazyMap")
    println("-----")
    println("first: ${lazyMap.first()}")
    println("-----")
    println("all: ${lazyMap.toList()}")
  1. Uruchom program i obserwuj dane wyjściowe. Drukowanie lazyMap powoduje tylko wydrukowanie odwołania do Sequence – wewnętrzna funkcja println() nie jest wywoływana. Drukowanie pierwszego elementu powoduje dostęp tylko do pierwszego elementu. Przekształcenie Sequence w List umożliwia dostęp do wszystkich elementów.
⇒ lazy: kotlin.sequences.TransformingSequence@5ba23b66
-----
access: rock
first: rock
-----
access: rock
access: pagoda
access: plastic plant
access: alligator
access: flowerpot
all: [rock, pagoda, plastic plant, alligator, flowerpot]
  1. Utwórz nowy Sequence, używając oryginalnego filtra przed zastosowaniem map. Wydrukuj ten wynik.
    val lazyMap2 = decorations.asSequence().filter {it[0] == 'p'}.map {
        println("access: $it")
        it
    }
    println("-----")
    println("filtered: ${ lazyMap2.toList() }")
  1. Uruchom program i obserwuj dodatkowe dane wyjściowe. Podobnie jak w przypadku pobierania pierwszego elementu, wewnętrzna funkcja println() jest wywoływana tylko w przypadku elementów, do których uzyskuje się dostęp.
⇒
-----
access: pagoda
access: plastic plant
filtered: [pagoda, plastic plant]

W tym zadaniu poznasz wyrażenia lambda i funkcje wyższego rzędu w Kotlinie.

Lambdy

Oprócz tradycyjnych funkcji nazwanych Kotlin obsługuje wyrażenia lambda. Lambda to wyrażenie, które tworzy funkcję. Zamiast deklarować funkcję nazwaną, deklarujesz funkcję bez nazwy. Przydatność tego rozwiązania polega na tym, że wyrażenie lambda można teraz przekazywać jako dane. W innych językach lambdy są nazywane funkcjami anonimowymi, literałami funkcji lub podobnie.

Funkcje wyższego rzędu

Funkcję wyższego rzędu możesz utworzyć, przekazując funkcję lambda do innej funkcji. W poprzednim zadaniu utworzyliśmy funkcję wyższego rzędu o nazwie filter. Do funkcji filter przekazano to wyrażenie lambda jako warunek do sprawdzenia:
{it[0] == 'p'}

Podobnie map jest funkcją wyższego rzędu, a przekazana do niej funkcja lambda była przekształceniem do zastosowania.

Krok 1. Dowiedz się więcej o funkcjach lambda

  1. Podobnie jak funkcje nazwane, lambdy mogą mieć parametry. W przypadku lambd parametry (i ich typy, jeśli są potrzebne) znajdują się po lewej stronie tzw. strzałki funkcji ->. Kod do wykonania znajduje się po prawej stronie strzałki funkcji. Gdy lambda zostanie przypisana do zmiennej, możesz ją wywołać tak samo jak funkcję.

    Używając REPL (Narzędzia > Kotlin > Kotlin REPL), wypróbuj ten kod:
var dirtyLevel = 20
val waterFilter = { dirty : Int -> dirty / 2}
println(waterFilter(dirtyLevel))
⇒ 10

W tym przykładzie funkcja lambda przyjmuje argument Int o nazwie dirty i zwraca wartość dirty / 2. (Filtracja usuwa zanieczyszczenia).

  1. Składnia typów funkcji w języku Kotlin jest ściśle powiązana ze składnią wyrażeń lambda. Aby w prosty sposób zadeklarować zmienną przechowującą funkcję, użyj tej składni:
val waterFilter: (Int) -> Int = { dirty -> dirty / 2 }

Oto treść kodu:

  • Utwórz zmienną o nazwie waterFilter.
  • waterFilter może być dowolną funkcją, która przyjmuje argument Int i zwraca argument Int.
  • Przypisz funkcję lambda do zmiennej waterFilter.
  • Funkcja lambda zwraca wartość argumentu dirty podzieloną przez 2.

Pamiętaj, że nie musisz już określać typu argumentu lambda. Typ jest obliczany przez wnioskowanie o typie.

Krok 2. Utwórz funkcję wyższego rzędu

Jak dotąd przykłady lambd przypominają głównie funkcje. Prawdziwa moc funkcji lambda polega na używaniu ich do tworzenia funkcji wyższego rzędu, w których argumentem jednej funkcji jest inna funkcja.

  1. Napisz funkcję wyższego rzędu. Oto podstawowy przykład funkcji, która przyjmuje 2 argumenty. Pierwszy argument jest liczbą całkowitą. Drugi argument to funkcja, która przyjmuje liczbę całkowitą i zwraca liczbę całkowitą. Wypróbuj go w REPL.
fun updateDirty(dirty: Int, operation: (Int) -> Int): Int {
   return operation(dirty)
}

Treść kodu wywołuje funkcję przekazaną jako drugi argument i przekazuje do niej pierwszy argument.

  1. Aby wywołać tę funkcję, przekaż jej liczbę całkowitą i funkcję.
val waterFilter: (Int) -> Int = { dirty -> dirty / 2 }
println(updateDirty(30, waterFilter))
⇒ 15

Przekazywana funkcja nie musi być lambdą. Może to być zwykła funkcja nazwana. Aby określić argument jako zwykłą funkcję, użyj operatora ::. Dzięki temu Kotlin wie, że przekazujesz odwołanie do funkcji jako argument, a nie próbujesz ją wywołać.

  1. Spróbuj przekazać zwykłą funkcję nazwaną do updateDirty().
fun increaseDirty( start: Int ) = start + 1

println(updateDirty(15, ::increaseDirty))
⇒ 16
var dirtyLevel = 19;
dirtyLevel = updateDirty(dirtyLevel) { dirtyLevel -> dirtyLevel + 23}
println(dirtyLevel)
⇒ 42
  • Aby utworzyć plik źródłowy Kotlin w IntelliJ IDEA, zacznij od projektu Kotlin.
  • Aby skompilować i uruchomić program w IntelliJ IDEA, kliknij zielony trójkąt obok funkcji main(). Dane wyjściowe pojawią się w oknie logu poniżej.
  • W IntelliJ IDEA określ argumenty wiersza poleceń, które mają być przekazywane do funkcji main() w Uruchom > Edytuj konfiguracje.
  • Prawie wszystko w Kotlinie ma wartość. Możesz wykorzystać ten fakt, aby uprościć kod, używając wartości if lub when jako wyrażenia lub wartości zwracanej.
  • Argumenty domyślne eliminują konieczność tworzenia wielu wersji funkcji lub metody. Na przykład:
    fun swim(speed: String = "fast") { ... }
  • Funkcje kompaktowe, czyli funkcje z jednym wyrażeniem, mogą zwiększyć czytelność kodu. Na przykład:
    fun isTooHot(temperature: Int) = temperature > 30
  • Poznaliśmy podstawy filtrów, które używają wyrażeń lambda. Na przykład:
    val beginsWithP = decorations.filter { it [0] == 'p' }
  • Wyrażenie lambda to wyrażenie, które tworzy funkcję nienazwaną. Wyrażenia lambda są definiowane w nawiasach klamrowych {}.
  • W funkcji wyższego rzędu przekazujesz funkcję, np. wyrażenie lambda, do innej funkcji jako dane. Na przykład:
    dirtyLevel = updateDirty(dirtyLevel) { dirtyLevel -> dirtyLevel + 23}

Ta lekcja zawiera dużo informacji, zwłaszcza jeśli dopiero zaczynasz przygodę z funkcjami lambda. W dalszej części kursu wrócimy do funkcji lambda i funkcji wyższego rzędu.

Dokumentacja języka Kotlin

Jeśli chcesz uzyskać więcej informacji na dowolny temat w tym kursie lub jeśli napotkasz trudności, najlepszym punktem wyjścia będzie strona https://kotlinlang.org.

Samouczki dotyczące języka Kotlin

Witryna https://try.kotlinlang.org zawiera rozbudowane samouczki Kotlin Koans, internetowy interpreter i pełny zestaw dokumentacji z przykładami.

Kurs Udacity

Aby obejrzeć kurs Udacity na ten temat, zobacz Kotlin Bootcamp for Programmers (w języku angielskim).

IntelliJ IDEA

Dokumentację IntelliJ IDEA znajdziesz w witrynie JetBrains.

W tej sekcji znajdziesz listę możliwych zadań domowych dla uczniów, którzy wykonują ten moduł w ramach kursu prowadzonego przez instruktora. Nauczyciel musi:

  • W razie potrzeby przypisz pracę domową.
  • Poinformuj uczniów, jak przesyłać projekty.
  • Oceń zadania domowe.

Instruktorzy mogą korzystać z tych sugestii w dowolnym zakresie i mogą zadawać inne zadania domowe, które uznają za odpowiednie.

Jeśli wykonujesz ten kurs samodzielnie, możesz użyć tych zadań domowych, aby sprawdzić swoją wiedzę.

Odpowiedz na te pytania

Pytanie 1

Funkcja contains(element: String) zwraca wartość true, jeśli ciąg znaków element znajduje się w ciągu znaków, w którym jest wywoływana. Jaki będzie wynik działania tego kodu?

val decorations = listOf ("rock", "pagoda", "plastic plant", "alligator", "flowerpot")

println(decorations.filter {it.contains('p')})

▢ [pagoda, plastic, plant]

▢ [pagoda, plastic plant]

▢ [pagoda, plastic plant, flowerpot]

▢ [rock, alligator]

Pytanie 2

W definicji funkcji poniżej który parametr jest wymagany?
fun shouldChangeWater (day: String, temperature: Int = 22, dirty: Int = 20, numDecorations: Int = 0): Boolean {...}

▢ numDecorations

▢ dirty

▢ day

▢ temperature

Pytanie 3

Do innej funkcji możesz przekazać zwykłą funkcję nazwaną (nie wynik jej wywołania). Jak przekazać increaseDirty( start: Int ) = start + 1 do updateDirty(dirty: Int, operation: (Int) -> Int)?

▢ updateDirty(15, &increaseDirty())

▢ updateDirty(15, increaseDirty())

▢ updateDirty(15, ("increaseDirty()"))

▢ updateDirty(15, ::increaseDirty)

Przejdź do następnej lekcji: 4. Klasy i obiekty

Omówienie kursu, w tym linki do innych ćwiczeń, znajdziesz w artykule „Kotlin Bootcamp for Programmers: Welcome to the course” (w języku angielskim).