Интересно, с точки зрения дизайна языка, почему 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 кодом (даже если фактическая реализация - это магия компилятора).