Skip to main content

Type Inference

Świetnie. Inferencja typów to kolejna koncepcja, która istnieje w nowszych wersjach Javy, ale w Kotlinie jest fundamentalną częścią języka od samego początku i jest stosowana znacznie szerzej.

6. Inferencja typów​

Inferencja typów to zdolność kompilatora do automatycznego wywnioskowania (wydedukowania) typu zmiennej, właściwości lub funkcji na podstawie kontekstu, najczęściej na podstawie wartości, która jest do niej przypisywana. W skrócie: nie musisz pisać typu, jeśli kompilator może go odgadnąć za Ciebie.


Znajomy grunt: var w Javie (od wersji 10)​

Jako doświadczony programista Javy, prawdopodobnie znasz słowo kluczowe var wprowadzone w Javie 10. Działa ono na tej samej zasadzie.

W Javie 10+:

// Kompilator wie, że 'name' jest typu String, bo przypisujesz mu literał stringowy.
var name = "Java";

// Kompilator wie, że 'numbers' to ArrayList<String>.
var numbers = new ArrayList<String>();

var w Javie jest jednak ograniczone głównie do zmiennych lokalnych.


Inferencja w Kotlinie: Standard, nie wyjątek​

W Kotlinie inferencja typów jest wszechobecna i jest standardowym, idiomatycznym sposobem pisania kodu. Stosuje się ją zarówno do val, jak i var.

Zamiast pisać tak (z jawnym typem):

val name: String = "Kotlin"
val score: Int = 100
val active: Boolean = true

Piszesz tak (z wywnioskowanym typem):

val name = "Kotlin"      // Kompilator wnioskuje: String
val score = 100 // Kompilator wnioskuje: Int
val active = true // Kompilator wnioskuje: Boolean
val price = 19.99 // Kompilator wnioskuje: Double
val items = listOf("A", "B") // Kompilator wnioskuje: List<String>

Kod staje się znacznie czystszy i mniej redundantny. Mniej pisania, ten sam efekt i to samo bezpieczeństwo typów. Kotlin nadal jest językiem statycznie typowanym – typ jest określany w czasie kompilacji, a nie w czasie wykonania.


Gdzie inferencja w Kotlinie idzie dalej niż var w Javie?​

Kotlin stosuje inferencję w wielu miejscach, nie tylko dla zmiennych lokalnych.

1. Właściwości klas (pola) Możesz pominąć typ właściwości, jeśli inicjujesz ją od razu w deklaracji.

class User {
val id = 123 // Inferred as Int
var username = "guest" // Inferred as String
val roles = setOf("USER") // Inferred as Set<String>
}

W Javie typ pola w klasie musi być zawsze zadeklarowany jawnie.

2. Funkcje zwracające wartość (w specyficznej formie) Dla funkcji, które składają się tylko z jednego wyrażenia (tzw. single-expression functions), nie musisz deklarować typu zwracanego. Kompilator wywnioskuje go z tego wyrażenia.

// Zamiast pisać:
fun double(x: Int): Int {
return x * 2
}

// Możesz napisać tak (typ zwracany Int jest wywnioskowany z `x * 2`):
fun double(x: Int) = x * 2

Uwaga: Dla funkcji z ciałem w bloku ({...}) musisz jawnie zadeklarować typ zwracany (jeśli nie jest to Unit, czyli void).


Kiedy musisz (lub powinieneś) podać typ jawnie?​

Inferencja jest świetna, ale są sytuacje, w których jest niemożliwa lub niewskazana.

1. Gdy nie ma wartości początkowej Jeśli deklarujesz zmienną bez jej inicjalizacji (co jest możliwe np. dla var lub właściwości z lateinit), kompilator nie ma z czego wywnioskować typu.

var name: String // OK, typ jest jawny
// var name // BŁĄD KOMPILACJI: Property must be initialized or be abstract

2. Gdy wartość początkowa to null null nie ma typu, więc kompilator nie wie, czy chodzi o String?, User? czy coś innego.

// val user = null // BŁĄD KOMPILACJI
val user: User? = null // OK, jawnie podajemy typ nullable

3. Gdy chcesz użyć typu nadrzędnego (programowanie do interfejsu) Czasami chcesz, aby zmienna miała typ bardziej ogólny (interfejs lub klasa nadrzędna) niż konkretna implementacja, którą tworzysz.

// Domyślnie typem będzie MutableList<String>
val names = mutableListOf("Ania", "Piotr")

// Jeśli chcesz, aby zmienna była widoczna jako niemodyfikowalna lista (dobra praktyka):
val readOnlyNames: List<String> = mutableListOf("Ania", "Piotr")

4. Dla czytelności w publicznych API W przypadku funkcji lub właściwości, które są częścią publicznego API biblioteki, dobrą praktyką jest jawne podawanie typów (zwłaszcza zwracanych). Dzięki temu kontrakt API jest jasny i czytelny bez potrzeby analizowania implementacji.

Podsumowanie dla programisty Javy​

KontekstJava (od 10+)Kotlin
Zmienna lokalnavar name = "Joe";val name = "Joe" (standard)
Pole / Właściwość klasyprivate String name = "Joe";val name = "Joe" (możliwe, jeśli jest inicjalizowana)
Typ zwracany funkcjiZawsze wymaganyOpcjonalny dla funkcji jednolinijkowych
FilozofiaOpcjonalna funkcja dla zwięzłościFundamentalna cecha języka

Inferencja typów w Kotlinie to nie tylko "lukier składniowy". To kluczowy element, który sprawia, że kod jest zwięzły, a jednocześnie w pełni bezpieczny pod względem typów.