Погружение в Kotlin (4): почему корневой тип Kotlin — Any?

Kotlin

Эта статья была размещена Prefert вScalaCoolБлог команды.

мы вПогружение в Kotlin (2): дизайн структуры типа KotlinСистема типов Kotlin была кратко представлена ​​в .

Упоминается в статье:AnyТипы в Котлиневсе ненулевые типы(бывший:String, Int) корневого типа.

Когда нам нужно взаимодействовать с Java, Kotlin использует параметры метода Java и возвращаемые типы, используемые вObjectвведите какAny(точнее как "тип платформы"). При использовании в функциях KotlinAny, он скомпилирован в байт-код JavaObject.

Что такое тип платформы?

Типы платформы — это, по сути, типы, для которых в Kotlin нет информации о допустимости значений NULL — все ссылочные типы Java ведут себя как типы платформы в Kotlin. При работе со значением типа платформы в Kotlin его можно рассматривать либо как тип, допускающий значение NULL, либо как ненулевой тип.

Введение типов платформ — это компромисс дизайна, когда Kotlin совместим с Java. Только представьте, если бы все значения из Java обрабатывались как ненулевые, было бы проще писать опасный код. И наоборот, если значения Java принудительно обнуляются, это приведет к большому количеству ошибок.nullОсмотр. Всестороннее рассмотрение, тип платформы является компромиссным дизайном.

В Яве,ObjectТипы находятся на верхнем уровне своей системы типов. Если Kotlin на 100 % совместим с Java, можем ли мы сказать, что Any также является типом верхнего уровня среди всех типов в Kotlin? В предыдущей статье меня эта проблема тоже беспокоила, а официал внятного заявления не сделал. Но что мы можем заметить, так это то, что в Kotlin была введена концепция «обнуляемых типов», которая, вероятно, повлияет на иерархию системы.

Прежде чем приступить к изучению корневых типов, давайте проясним два понятия: наследование (Inheriting) и подтип (Subtyping).

Разница между наследованием и подтипом

Это, казалось бы, легкий, но не такой уж простой вопрос: что же такое подтипирование (Subtyping)? мы былиПодтипы и классы типов (1)В этом блоге обсуждается этот вопрос. Если у вас есть только опыт разработки на языке программирования Java, легко впасть в заблуждение — отношение наследования определяет отношение типа родитель-потомок. Потому что в Java классы и типы в большинстве случаев «эквивалентны» (до дженериков Java).

На самом деле «наследование» и «подтипирование» — это два совершенно разных понятия.

  • подтипЯдром является отношение замещения типа (мы также можем назвать его полиморфизмом подтипа), которое обычно может быть выражено как:

    S <: T
    

    вышеSдаTподкласс , что означает, что когда вам нужноTгде значение типа,SЗначения типов тоже работают, как в КотлинеIntдаNumberПодкласс:

    fun printNum(num: Number) {
      println(num)
    }
    
    >>> val n: Int = 1
    >>> printNum(n)
    
    >>> 1
    >>> printNum("I am a String")
    error: type mismatch: inferred type is String but Number was expected
    
  • Условно говоря,наследоватьУпор делается на своего рода «повторное использование реализации», а подтипирование — это отношение семантики типов, не имеющее ничего общего с реализацией. В Java мы, похоже, также можем достичь вышеуказанных отношений с помощью наследования классов:

    class S extends class T
    

    Поскольку отношение наследования также объявляется при объявлении отношения типа родитель-потомок, это обычно вызывает некоторую путаницу, но это не означает, что эти два понятия эквивалентны.

Несмотря на то чтоAnyиAny?Кажется, что нет никакого отношения наследования, но когда нам нужно использоватьAny?Там, где значение типа, очевидно, вы можете передать типAnyvalue, что не вызывает проблем при компиляции. Обратное не работает, например: тип параметраAnyфункцию, мы передаем вAny?Типnullзначение, возникает следующая ошибка:

error: null can not be a value of a non-null type Any

Из вышеизложенного также можно сделать предварительные выводы:AnyЗначение можно заменить во всех случаяхAny?значение, которое соответствует концепции «подтипирования».

Поэтому смело можем сказать:В системе типов КотлинаAny?даAnyсупертип и является корневым типом всех типов, хотя текущая документация официального сайта Kotlin не распространяется на это.

Любой? и Любой??

Один вопрос, который вы могли бы оспорить, заключается в том, еслиAny?даAnyсупертип , тоAny??это сноваAny?Супертип , если это правда, значит ли это, что нет так называемого «корневого типа всех типов»?

На самом деле типы, допускающие значение NULL, в Kotlin можно рассматривать как так называемыеUnion Type, обычно используется в программеA | BПредставление, приближение объединения в математике. Если представлено объединением типовAny?, что можно записать какAny ∪ Null. соответствующийAny??выражается какAny ∪ Null ∪ Null, что эквивалентноAny ∪ Null, Прямо сейчасAny??ЭквивалентноAny?. Поэтому, скажемAny?Не проблема быть корневым типом всех типов.