Один из вариантов использования встроенного класса.
Некоторое время назад, до того, как Kotlin представил встроенные классы, я создавал небольшой виджет, который должен был преобразовывать градусы Фаренгейта в градусы Цельсия и наоборот.
Поскольку оба они представлены как Double, я решил использовать псевдонимы типов для их разделения. Я подумал, что это крутая идея, поэтому я уволился и объявил свои псевдонимы типов и построил функции для их преобразования.
typealias Fahrenheit = Double typealias Celsius = Double fun convert(value: Fahrenheit): Celsius = TODO() fun convert(value: Celsius): Fahrenheit = TODO()
Первая проблема, вы не можете этого сделать. Компилятор Kotlin не может отличить две подписи друг от друга. То же самое относится и к выражению when. Пока значение равно Double, оно всегда будет давать истину в выражении по Фаренгейту. Компилятор также скажет «Duplicate label in when» для псевдонимов двух типов.
return when(value) { is Fahrenheit -> TODO() is Celsius -> TODO() } // The above is actually resulting in this: return when(value) { is Double -> TODO() is Double -> TODO() }
Честно говоря, при следующей попытке расширение функционирует. И теперь семантика моей функции имеет особенность, которая радует компилятор.
fun Fahrenheit.toCelsius(): Celsius = TODO() fun Celsius.toFahrenheit(): Fahrenheit = TODO()
Итак, теперь я могу писать довольно приятный код, и при чтении кода становится понятно, что к чему. Но это все зависит от разработчика и никаким образом не обеспечивается кодом или структурой.
val temperature: Fahrenheit = 0.0 val temperature2 = temperature.toFahrenheit()
Мы могли бы связывать «по Фаренгейту» или «по Цельсию» навсегда, не получая никаких ошибок кода, а только с ошибочными значениями.
Итак, в этот раз я сдался и отправил на Kotlin lang предложение исправить применяемые псевдонимы типов. И они думали, что это плохая идея для псевдонимов типов. Примерно через год была объявлена функция встроенного класса, и я, наконец, смог написать идиоматический код, который хотел тогда. Вот как:
inline class Fahrenheit(val degree:Double) inline class Celsius(val degree:Double) fun convert(degree: Fahrenheit): Celsius = TODO() fun convert(degree: Celsius): Fahrenheit = TODO() fun Fahrenheit.toCelsius(): Celsius = TODO() fun Celsius.toFahrenheit(): Fahrenheit = TODO() val temperature = Fahrenheit(0.0) val c = temperature.toCelsius() // can't call toFahrenheit here
А теперь будем надеяться, что скоро он выйдет из экспериментального. Https://kotlinlang.org/docs/reference/inline-classes.html#experimental-status-of-inline-classes
На данный момент существует несколько ограничений для встроенных классов. Но это уже другая история. Если вы хотите начать, вот официальная документация: https://kotlinlang.org/docs/reference/inline-classes.html
Спасибо за уделенное время!
→ Боб