Встроенные классы в Котлине

Встроенные классы в Котлине

1. обзор

В Kotlin 1.3+ у нас есть экспериментальный новый тип класса под названиемinline class. В этом руководстве мы сосредоточимся на использовании встроенных классов, а также на некоторых их ограничениях.

2. Настроить

Как мы упоминали ранее, встроенные классы являются экспериментальной особенностью Kotlin. Как следствие, компилятор выдастwarning, указывающий на экспериментальный статус функции.

Чтобы избежать этого предупреждения, мы можем добавить в нашу конфигурацию следующиеMaven compiler option:


    
        -XXLanguage:+InlineClasses
    

3. Что такое встроенные классы

Встроенные классы предоставляют нам способ обернуть тип, таким образом добавляя функциональность и создавая новый тип сам по себе.

В отличие от обычных (не встроенных) оболочек, они получат выгоду от улучшенной производительности. Это происходит потому, что данные встроены в их использование, и создание экземпляра объекта в результирующем скомпилированном коде пропускается.

Давайте посмотрим на пример встроенного классаInlinedCircleRadius со свойством типаDouble, представляющим радиус:

val circleRadius = InlinedCircleRadius(5.5)

Для JVM наш код на самом деле просто:

val circleRadius = 5.5

Обратите внимание, как нашInlinedCircleRadius не создается в скомпилированном коде, потому что базовое значение встроено, что избавляет нас от потерь производительности, связанных с созданием экземпляра.

3.1. Пример использования

Теперь, когда мы знаем, что такое встроенные классы, мы обсудим их использование.

A single property initialized in the primary constructor is the basic requirement of aninline class. Единственное свойство будет представлять экземпляр класса во время выполнения.

Поэтому, чтобы иметь правильное определение, мы можем использовать одну строку кода:

inline class InlineDoubleWrapper(val doubleValue : Double)

Мы определилиInlineDoubleWrapper как простую оболочку над объектомDouble и применили к нему ключевое словоinline. Наконец, теперь мы можем использовать этот класс в нашем коде без дополнительных изменений:

@Test
fun whenInclineClassIsUsed_ThenPropertyIsReadCorrectly() {
    val piDoubleValue = InlineDoubleWrapper(3.14)
    assertEquals(3.14, piDoubleValue.doubleValue)
}

4. Члены класса

До сих пор мы использовали встроенные классы, как простые обертки. Но они намного больше, чем это. They also allow us to define properties and functions just like regular classes. В следующем примере определяется свойство, представляющее диаметр, и функция, возвращающая площадь круга:

inline class CircleRadius(private val circleRadius : Double) {
    val diameterOfCircle get() = 2 * circleRadius
    fun areaOfCircle = 3.14 * circleRadius * circleRadius
}

Теперь создадим тест для нашего свойстваdiameterOfCircle. Он создаст экземпляр нашего встроенного классаCircleRadius, а затем вызовет свойство:

@Test
fun givenRadius_ThenDiameterIsCorrectlyCalculated() {
    val radius = CircleRadius(5.0)
    assertEquals(10.0, radius.diameterOfCircle)
}

А вот простой тест для функцииareaOfCircle:

@Test
fun givenRadius_ThenAreaIsCorrectlyCalculated() {
    val radius = CircleRadius(5.0)
    assertEquals(78.5, radius.areaOfCircle())
}

Однако есть некоторые ограничения на то, что мы можем и не можем определять внутри наших встроенных классов. While properties and functions are allowed, we have to mention that init blocks, inner classes, and backing fields are not.с

5. наследование

Важно отметить, чтоinline classes can inherit only from interfaces, и поскольку у нас не может быть подклассов,inline classes are also effectively final.

Учитывая интерфейсDrawable с методомdraw(), мы реализуем этот метод в нашем классеCircleRadius:

interface Drawable {
    fun draw()
}

inline class CircleRadius(private val circleRadius : Double) : Drawable {
    val diameterOfCircle get() = 2 * circleRadius
    fun areaOfCircle() = 3.14 * circleRadius * circleRadius

    override fun draw() {
        println("Draw my circle")
    }
}

6. Выводы

В этой быстрой статье мы рассмотрели встроенные классы в Kotlin. Кроме того, мы говорили о наследовании и определении свойств и функций.

Как обычно, все эти примеры и фрагменты можно найтиover on GitHub.