Интегрированный класс Kotlin в тестах JUnit - PullRequest
2 голосов
/ 26 мая 2019

Я пытаюсь понять концепцию встроенных классов - они представляют собой простую обертку объекта с одним свойством, которое встроено во время выполнения.Это означает, что фактическая инициализация класса не происходит во время выполнения

Я пытался написать простой тест, который непосредственно покажет мое объяснение выше во время теста JUnit, как показано ниже:

companion object {
   private const val NAME = "JACK"
}

inline class NameInlineClass(val value: String)

@Test
fun unwrapping() {
    val nameInlineClass = NameInlineClass(NAME)
    val name = nameInlineClass
    assertEquals(name, NAME)
}

К сожалению, этот тест не проходит, что приводит меня к вопросу, почему во время assertEquals() фактическое развернутое значение String сравнивается не с реальным встроенным классом (который должен быть развернут во время выполнения)?

1 Ответ

5 голосов
/ 26 мая 2019

Что вы, вероятно, хотели сделать, это val name = nameInlineClass.value, но я попытаюсь объяснить ошибку.

См. Представление из документов (включая пример кода):

В сгенерированном коде компилятор Kotlin сохраняет оболочку для каждого встроенного кода учебный класс. Встроенные экземпляры классов могут быть представлены во время выполнения как обертки или как базовый тип. Это похоже на то, как Int может быть представляется либо как примитив int, либо как целочисленная оболочка.

Это означает, что до тех пор, пока вы не будете ссылаться на объект обтекания или его тип явно, значение не будет упаковано. Мы можем проверить это, проверив байт-код (декомпилированный обратно в Java для удобства чтения):

// kotlin source
fun unwrapping() {
    val nameInlineClass = NameInlineClass(NAME)
    val name = nameInlineClass  // this line gets dropped by compiler by the way
    assertEquals(name, NAME)
}

// java representation of bytecode
public final void unwrapping() {
   String nameInlineClass = NameInlineClass.constructor-impl("JACK");
   Assert.assertEquals(NameInlineClass.box-impl(nameInlineClass), "JACK");
}

Я не буду вставлять все сгенерированное NameInlineClass тело, но constructor-impl - статический метод, который проверяет только null из value, а box-impl создает объект-оболочку.

Как видите, nameInlineClass - это действительно String - это означает, что встроенные операции не выполняются, и никакой дополнительный объект не был выделен.

Только когда вы ссылаетесь на nameInlineClass вместо nameInlineClass.value, компилятор определяет, что этот объект нуждается в представлении и "помещает" значение в обертку NameInlineClass class.

...