Интересно, с точки зрения дизайна языка, почему Scala удалил литерал класса Java (например, String.class
) и заменил его на classOf[String]
, но затем добавил "литерал типа" с его синглонами, например Singleton.type
что-то вроде typeOf[Singleton]
?
Scala.type и Java.class literal
Ответ 1
Вот моя рационализация:
classOf [Т]
classOf
определяется в Predef
как функция с этой сигнатурой:
def classOf[T]: Class[T]
Хотя он реализован компилятором, использование синтаксиса функции возможно без необходимости создания какой-либо специальной обработки с точки зрения синтаксиса. Так что одна причина здесь, чтобы рассмотреть этот вариант.
Альтернатива, подобная String.class
, подразумевает, что каждый класс имеет объект-компаньон с полем class
. Таким образом, есть две проблемы:
-
class
- это ключевое слово, поэтому возникает проблема, когда для синтаксиса для него требуется специальный случай - Если вы просто создаете
class A
без объекта-компаньона, было бы странно иметь возможность ссылаться наA.class
, что было бы похоже на доступ к полю класса на компаньонеA
.
A.type:
Почему typeOf[A]
может ввести в заблуждение. Это похоже на вызов функции, но типы не живут в том же мире, что и результаты функции (результаты функции имеют типы, но сам тип имеет смысл только во время компиляции). Я могу приписать тип переменной:
scala> val a: A.type = A
a: A.type = [email protected]
Я не могу назначить тип, подобный возвращаемому функцией:
scala> val b = A.type
<console>:1: error: identifier expected but 'type' found.
val b = A.type
^
С другой стороны, типы могут быть членами объекта:
scala> object A { type type1 = Int }
defined module A
scala> val x: A.type1 = 1
x: A.type1 = 1
Таким образом, не имеет большого значения A.type
, относящегося к типу объекта A
. Обратите внимание, что .type
не используются для ссылок на типы одноэлементных объектов, поэтому на самом деле это не так часто.
Ответ 2
Собственно, он вполне последователен. Singleton.type
является зависимым типом Singleton
, а classOf[Class]
является параметром типа для метода.
Рассмотрим это:
class A {
class B
}
val a: A = new A
val b: a.B = new a.B
Дело в том, что .
используется для указания того, что является членом значения. Это может быть val
, a var
, a def
или object
, а также может быть type
, a class
или trait
.
Поскольку одноэлементный объект является значением, тогда Singleton.type
отлично действует.
С другой стороны, класс не является объектом, поэтому Class.class
не имеет смысла. class
не существует (как значение), поэтому его невозможно получить. С другой стороны, это определение как def classOf[T]: Class[T]
является простым Scala кодом (даже если фактическая реализация - это магия компилятора).