Nauka języka programowania Kotlin

Kotlin to język programowania, przez programistów aplikacji na Androida na całym świecie. Ten temat pełni funkcję Kotlin aby szybko rozpocząć pracę.

Deklaracja zmiennej

Kotlin używa do deklarowania zmiennych dwóch różnych słów kluczowych: val i var.

  • Użyj val w przypadku zmiennej, której wartość nigdy się nie zmienia. Nie można ponownie przypisać wartości do zmiennej zadeklarowanej za pomocą funkcji val.
  • Podaj zmienną var, której wartość może się zmieniać.

W poniższym przykładzie count jest zmienną typu Int, do której przypisano wartość wartość początkowa 10:

var count: Int = 10

Int to typ reprezentujący liczbę całkowitą, jeden z wielu typów liczbowych, można zapisać w Kotlin. Podobnie jak w przypadku innych języków, możesz także użyć Byte, Short, Long, Float i Double w zależności od Twoich danych liczbowych.

Słowo kluczowe var oznacza, że w razie potrzeby możesz ponownie przypisać wartości do konta count. Dla: na przykład możesz zmienić wartość count z 10 na 15:

var count: Int = 10
count = 15

Niektórych wartości nie należy jednak zmieniać. Weźmy pod uwagę: String o nazwie languageName Jeśli chcesz mieć pewność, że languageName zawsze zawiera wartość „Kotlin”, możesz zadeklarować languageName za pomocą słowa kluczowego val:

val languageName: String = "Kotlin"

Te słowa kluczowe jasno określają, co można zmienić. Wykorzystaj je, aby: Twoją korzyść. Jeśli odwołanie do zmiennej musi być możliwe do ponownego przypisania, zadeklaruj go jako var. W przeciwnym razie użyj val.

Wnioskowanie typu

Kontynuując poprzedni przykład: gdy przypiszesz wartość początkową do languageName, kompilator Kotlin może wywnioskować typ na podstawie typu przypisanej wartości.

Wartość "Kotlin" jest typu String, więc kompilator określa, że languageName ma też status String. Zwróć uwagę, że Kotlin to narzędzie wpisane statycznie. język. Oznacza to, że typ jest rozpoznawany w czasie kompilacji i nigdy zmian.

W poniższym przykładzie pole languageName zostało określone jako String, więc nie można wywołaj dowolne funkcje, które nie należą do klasy String:

val languageName = "Kotlin"
val upperCaseName = languageName.toUpperCase()

// Fails to compile
languageName.inc()

toUpperCase() to funkcja, która może być wywoływana tylko dla zmiennych danego typu String Kompilator Kotlin wywnioskował, że languageName to String, możesz bezpiecznie zadzwonić pod numer toUpperCase(). inc() jest natomiast operatorem Int , więc nie może zostać wywołana przez String. Podejście Kotlina do pisania wnioskowanie zapewnia zarówno zwięzłość, jak i bezpieczeństwo typów.

Poziom bezpieczeństwa o wartości null

W przypadku niektórych języków zmienną typu referencyjnego można zadeklarować bez podawania początkowa wartość jawna. W takich przypadkach zmienne zwykle zawierają wartość null. . Zmienne Kotlin nie mogą domyślnie zawierać wartości null. Oznacza to, że ten fragment jest nieprawidłowy:

// Fails to compile
val languageName: String = null

Aby zmienna zawierała wartość null, musi być typu dopuszczalna wartość null. Dostępne opcje określ zmienną jako dopuszczalną do wartości null, dodając do jej typu sufiks ?, jak pokazano w tym przykładzie:

val languageName: String? = null

W przypadku typu String? możesz przypisać wartość String lub null do languageName

Trzeba ostrożnie obchodzić się ze zmiennymi dopuszczającymi wartości null, ponieważ w przeciwnym razie pojawi się ryzyko NullPointerException Jeśli na przykład w Javie spróbujesz wywołać metodę na wartości null, program ulega awarii.

Kotlin udostępnia wiele mechanizmów do bezpiecznej pracy z wartościami null zmiennych. Więcej informacji: Typowe wzorce Kotlin w Androidzie: dopuszczalność wartości null.

Warunkowe

Kotlin udostępnia kilka mechanizmów do implementacji logiki warunkowej. Najbardziej jest z nich np. if-else. Jeśli wyrażenie zawiera w nawiasie obok słowa kluczowego if zwraca wynik true, a następnie kod w obrębie tej gałęzi (czyli kod następujący po nim zapakowany w zakrętkę) nawiasy klamrowe). W przeciwnym razie wykonywany jest kod w gałęzi else.

if (count == 42) {
    println("I have the answer.")
} else {
    println("The answer eludes me.")
}

Za pomocą else if możesz przedstawić wiele warunków. Dzięki temu możesz reprezentować bardziej szczegółową, skomplikowaną logikę w ramach pojedynczej instrukcji warunkowej, jak widać w instrukcjach następujący przykład:

if (count == 42) {
    println("I have the answer.")
} else if (count > 35) {
    println("The answer is close.")
} else {
    println("The answer eludes me.")
}

Wyrażenia warunkowe przydają się do przedstawiania logiki stanowej, ale że powtarzają się przy ich pisaniu. W przykładzie powyżej po prostu wydrukuj String w każdej gałęzi. Aby uniknąć takich powtórzeń, Kotlin oferuje wyrażenia warunkowe. Ostatni przykład można zapisać tak:

val answerString: String = if (count == 42) {
    "I have the answer."
} else if (count > 35) {
    "The answer is close."
} else {
    "The answer eludes me."
}

println(answerString)

Oznacza to, że każda gałąź warunkowa zwraca wynik wyrażenia na ostatni wiersz, więc nie musisz używać słowa kluczowego return. Ponieważ w wyniku wszystkie 3 gałęzie są typu String, wynikiem wyrażenia if-else jest również typu String. W tym przykładzie do pola answerString przypisano inicjał z wyniku wyrażenia if-else. Wykorzystanie wnioskowania typu do: pomiń deklarację jednoznacznego typu dla answerString, ale często jest to dobre uwzględnić go w celu uniknięcia wątpliwości.

Wraz ze wzrostem złożoności stwierdzenia warunkowego możesz rozważyć: zastępując wyrażenie „if-else” wyrażeniem when, jak widać w następujący przykład:

val answerString = when {
    count == 42 -> "I have the answer."
    count > 35 -> "The answer is close."
    else -> "The answer eludes me."
}

println(answerString)

Każda gałąź w wyrażeniu when jest reprezentowana przez warunek, strzałka (->) i wynik. Jeśli warunek po lewej stronie strzałki zwraca wartość prawda, wynik wyrażenia po prawej stronie wynosi . Pamiętaj, że wykonanie nie następuje pomiędzy gałęziami. Kod w przykładowym wyrażeniu when jest funkcjonalnie odpowiednikiem kodu w z poprzednim przykładem, ale jest po prostu łatwiejsza do odczytania.

Fragmenty warunkowe Kotlina podkreślają jedną z bardziej zaawansowanych funkcji, inteligentne przesyłanie. Zamiast używać operatora bezpiecznego połączenia lub parametru not-null do pracy z wartościami dopuszczającymi wartości null, możesz zamiast tego sprawdzić, czy zawiera odniesienie do wartości null za pomocą instrukcji warunkowej, jak w tym przykładzie:

val languageName: String? = null
if (languageName != null) {
    // No need to write languageName?.toUpperCase()
    println(languageName.toUpperCase())
}

W gałęzi warunkowej pole languageName może być traktowane jako niedopuszczone do wartości null. Kotlin jest na tyle inteligentny, że potrafi rozpoznać, że warunek wykonania gałęzi jest to, że languageName nie zawiera wartości null, więc nie trzeba traktować languageName na wartość null w tej gałęzi. To inteligentne przesyłanie działa w przypadku null sprawdzanie, sprawdzanie typu, lub dowolny warunek, który spełnia umowa.

Funkcje

W funkcji możesz zgrupować jedno lub więcej wyrażeń. Zamiast powtarzać za każdym razem, gdy potrzebujesz wyniku, możesz zawijać tę samą serię wyrażeń wyrażenia w funkcji i wywołaj tę funkcję.

Aby zadeklarować funkcję, użyj słowa kluczowego fun, a po nim nazwy funkcji. Następnie zdefiniuj typy danych wejściowych, które może przyjmować funkcja (o ile takie dane ma) i zadeklaruj typ zwracanych danych wyjściowych. Treść funkcji to miejsce, w którym określasz wyrażenia, które są wywoływane podczas wywoływania funkcji.

Nawiązując do poprzednich przykładów, przedstawiamy kompletną funkcję Kotlina:

fun generateAnswerString(): String {
    val answerString = if (count == 42) {
        "I have the answer."
    } else {
        "The answer eludes me"
    }

    return answerString
}

Funkcja w powyższym przykładzie ma nazwę generateAnswerString. it nie pobiera żadnych danych. Zwraca wynik typu String. Aby wywołać użyj jej nazwy, a po niej operatora wywołania (()). W w poniższym przykładzie zmienna answerString jest inicjowana na podstawie wyniku generateAnswerString()

val answerString = generateAnswerString()

Funkcje mogą przyjmować argumenty jako dane wejściowe, jak w tym przykładzie:

fun generateAnswerString(countThreshold: Int): String {
    val answerString = if (count > countThreshold) {
        "I have the answer."
    } else {
        "The answer eludes me."
    }

    return answerString
}

Deklarując funkcję, możesz podać dowolną liczbę argumentów i ich . W powyższym przykładzie generateAnswerString() przyjmuje 1 argument o nazwie countThreshold typu Int. Możesz w niej odwołać się do funkcji używając jego nazwy.

Wywołanie tej funkcji wymaga umieszczenia w niej argumentu nawiasy okrągłe:

val answerString = generateAnswerString(42)

Uproszczenie deklaracji funkcji

generateAnswerString() to dość prosta funkcja. Funkcja deklaruje parametr i natychmiast zwraca. Gdy wynikiem pojedynczego wyrażenia jest zwracanych przez funkcję, możesz pominąć deklarowanie zmiennej lokalnej, bezpośrednio zwracający wynik wyrażenia if-else zawartego w funkcji, w tym przykładzie:

fun generateAnswerString(countThreshold: Int): String {
    return if (count > countThreshold) {
        "I have the answer."
    } else {
        "The answer eludes me."
    }
}

Zwracane słowo kluczowe możesz też zastąpić operatorem przypisania:

fun generateAnswerString(countThreshold: Int): String = if (count > countThreshold) {
        "I have the answer"
    } else {
        "The answer eludes me"
    }

Funkcje anonimowe

Nie każda funkcja wymaga nazwy. Niektóre funkcje są bardziej bezpośrednio identyfikowane przez oraz ich dane wejściowe i wyjściowe. Są one nazywane funkcjami anonimowymi. Ty może zachować odwołanie do funkcji anonimowej, używając tego odwołania do później można wywołać funkcję anonimową. Możesz też przekazać odnośnik wokół swojego aplikacji, tak jak w przypadku innych typów plików referencyjnych.

val stringLengthFunc: (String) -> Int = { input ->
    input.length
}

Podobnie jak funkcje nazwane, funkcje anonimowe mogą zawierać dowolną liczbę wyrażeń. Wartość zwrócona funkcji jest wynikiem wyrażenia końcowego.

W powyższym przykładzie stringLengthFunc zawiera odniesienie do anonimowego funkcja, która jako dane wejściowe przyjmuje String i zwraca długość danych wejściowych String jako dane wyjściowe typu Int. Dlatego typ funkcji to opisana jako (String) -> Int. Nie wywołuje on jednak funkcji. Aby pobrać wynik funkcji, musisz wywołać ją tak samo jak funkcji nazwanej. Wywołanie stringLengthFunc wymaga podania wartości String jako w tym przykładzie:

val stringLengthFunc: (String) -> Int = { input ->
    input.length
}

val stringLength: Int = stringLengthFunc("Android")

Funkcje wyższego rzędu

Funkcja może przyjąć inną funkcję jako argument. Funkcje korzystające z innych funkcji funkcje jako argumenty są nazywane funkcjami wyższego rzędu. Ten wzorzec jest przydatne do komunikacji między komponentami w taki sam sposób, jak interfejsu wywołania zwrotnego w Javie.

Oto przykład funkcji wyższego rzędu:

fun stringMapper(str: String, mapper: (String) -> Int): Int {
    // Invoke function
    return mapper(str)
}

Funkcja stringMapper() przyjmuje funkcję String i funkcję, która pobiera wartość Int z przekazanej do niej wartości String.

Możesz wywołać funkcję stringMapper(), przekazując element String i funkcję, która spełnia drugi parametr wejściowy, czyli funkcję, która przyjmuje funkcję String jako wprowadza i zwraca Int, jak w tym przykładzie:

stringMapper("Android", { input ->
    input.length
})

Jeśli funkcja anonimowa jest parametrem last zdefiniowanym w funkcji, możesz poza nawiasami używanymi do wywołania funkcji, jak pokazano w następujący przykład:

stringMapper("Android") { input ->
    input.length
}

Funkcje anonimowe można znaleźć w całej bibliotece standardowej Kotlin. Dla: więcej informacji znajdziesz w Funkcje wyższego rzędu i lambda.

Zajęcia

Wszystkie wymienione do tej pory typy są wbudowane w program Kotlin. język. Jeśli chcesz dodać własny typ niestandardowy, możesz zdefiniować klasę ze słowem kluczowym class, jak w tym przykładzie:

class Car

Właściwości

Klasy reprezentują stan za pomocą właściwości. O property to zmienną na poziomie klasy, która może zawierać metodę getter, setter i pole Backing. Ponieważ samochód do jazdy potrzebuje kół, możesz dodać listę obiektów Wheel jako właściwości Car, jak w tym przykładzie:

class Car {
    val wheels = listOf<Wheel>()
}

Pamiętaj, że wheels to public val, co oznacza, że dostęp do usługi wheels można uzyskać z poziomu spoza zajęć Car i nie można go przypisać. Jeśli chcesz uzyskać instancji Car, musisz najpierw wywołać jego konstruktor. Opcje dostępne na tej stronie uzyskać dostęp do dostępnych właściwości.

val car = Car() // construct a Car
val wheels = car.wheels // retrieve the wheels value from the Car

Jeśli chcesz dostosować koła, możesz zdefiniować własny konstruktor, określa sposób inicjowania właściwości klasy:

class Car(val wheels: List<Wheel>)

W powyższym przykładzie konstruktor klas przyjmuje List<Wheel> jako jako argumentu konstruktora, który wykorzystuje ten argument do zainicjowania argumentu wheels usłudze.

Funkcje klasy i hermetyzacja

Klasy używają funkcji do modelowania zachowań. Funkcje mogą zmieniać stan, aby ujawnić tylko te dane, które chcesz ujawnić. Ta kontrola dostępu jest częścią bardziej zorientowaną na obiekt, nazywaną enkapsulacją.

W poniższym przykładzie właściwość doorLock jest prywatna. spoza klasy Car. Aby odblokować samochód, musisz zadzwonić pod numer unlockDoor() w postaci prawidłowego klucza, jak w tym przykładzie:

class Car(val wheels: List<Wheel>) {

    private val doorLock: DoorLock = ...

    fun unlockDoor(key: Key): Boolean {
        // Return true if key is valid for door lock, false otherwise
    }
}

Jeśli chcesz dostosować sposób odwołań do właściwości, możesz podać metody getter i seter. Na przykład, jeśli chcesz ujawnić getter, ograniczając dostęp do metody ustawiającej, możesz wyznaczyć ją jako private:

class Car(val wheels: List<Wheel>) {

    private val doorLock: DoorLock = ...

    var gallonsOfFuelInTank: Int = 15
        private set

    fun unlockDoor(key: Key): Boolean {
        // Return true if key is valid for door lock, false otherwise
    }
}

Dzięki połączeniu właściwości i funkcji możesz tworzyć klasy, które modelowanie wszystkich typów obiektów.

Interoperacyjność

Jedną z najważniejszych cech usługi Kotlin jest płynna interoperacyjność z językiem Java. Kod Kotlin kompiluje się do kodu bajtowego JVM, więc może wywoływać metodę bezpośrednio do kodu Java i odwrotnie. Oznacza to, że możesz korzystać z istniejących bibliotek Java bezpośrednio w kotlinie. Ponadto większość Interfejsy API Androida są napisane w języku Java i można je wywoływać bezpośrednio w Kotlin.

Dalsze kroki

Kotlin to elastyczny, pragmatyczny język, który zyskuje na popularności i wsparciu. Śr zachęcamy do jej wypróbowania, jeśli jeszcze jej nie znasz. Sprawdź, co jeszcze możesz zrobić w oficjalnej dokumentacji Kotlin wraz z instrukcją przesyłania popularnych wzorców Kotlin w Twoich aplikacjach na Androida.