programowanieProgramista Backend

Czym jest 'inline class' (value class) w Kotlinie? Do czego są potrzebne, jak je prawidłowo używać, jakie ograniczenia i cechy mają takie klasy? Podaj przykłady kodu.

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź

inline class (od Kotlin 1.5 — value class) pozwala na tworzenie wrapperów nad typami prymitywnymi bez tworzenia osobnego obiektu w czasie wykonania. Jest to używane w celu zwiększenia typowej bezpieczeństwa bez kosztów związanych z alokacją pamięci. Pod maską takie obiekty mogą być kompilowane do odpowiedniego typu prymitywnego.

Przykład:

@JvmInline value class UserId(val id: String) fun printUserId(userId: UserId) { println(userId.id) }
  • Dozwolone jest tylko jedno pole (pole podstawowe).
  • Nie jest możliwy konstruktor bezargumentowy.
  • Klasa nie może przechowywać stanu (np. pola var), tylko val.
  • Nie można dziedziczyć inne klasy, ale można implementować interfejsy.
  • Interakcja z kodem Java może być nieoczywista — występuje możliwość boxing/unboxing.

Użycie inline/value klas jest ważne dla typizacji identyfikatorów, pieniędzy, jednostek miary itd.

Pytanie z podstępem

Czy value class może mieć więcej niż jedną właściwość?

Odpowiedź: Nie. Value class może zawierać tylko jedną właściwość w konstruktorze głównym.

Przykład błędnego kodu:

@JvmInline value class Money(val amount: Int, val currency: String) // Błąd kompilacji

Przykłady rzeczywistych błędów z powodu niewiedzy o szczegółach tematu


Historia

W kantorze walutowym zastosowano inline class do opisania kwoty i waluty. Próbowano dodać dwa pola do value class, otrzymano błąd kompilacji i spędzono trochę czasu na próbie obejścia ograniczenia. W końcu zdecydowano się na użycie osobnej klasy danych.


Historia

Podczas integracji z zewnętrzną biblioteką Java, inline class czasami nieoczekiwanie przekształcał się w obiekt (boxing), co wpłynęło na wydajność. Po analizie dokumentacji zastąpiono go zwykłym obiektem wartości.


Historia

W projekcie z mikroserwisami używano value class jako identyfikatorów w API. Jeden z serwisów zwracał ciąg znaków bezpośrednio, inny — value class, co doprowadziło do konfliktu serializacji z Jackson. Naprawiono poprzez jawne mapowanie między id i ciągiem znaków.