Начиная с Scala 2.7.2 существует что-то позвонившее Manifest
который является обходным решением для стирания типа Java. Но как делает Manifest
работайте точно и почему / когда необходимо будет использовать его?
Декларации сообщения в блоге: Овеществленные Типы Jorge Ortiz объясняют часть его, но это не объясняет, как использовать его вместе с границами контекста.
Кроме того, что ClassManifest
, с чем различие Manifest
?
У меня есть некоторый код (часть большей программы, не может легко включать его здесь), который имеет некоторые предупреждения относительно стирания типа; я подозреваю, что могу решить их при помощи деклараций, но я не уверен точно как.
Компилятор знает больше информации о типах, чем среда выполнения JVM может легко представить. Манифест - это способ компилятора отправить межпространственное сообщение коду во время выполнения о потерянной информации о типе.
Это похоже на то, как клептонианцы оставили закодированные сообщения в окаменелостях и «мусорной» ДНК людей. Из-за ограничений скорости света и полей гравитационного резонанса они не могут общаться напрямую. Но, если вы знаете, как настроиться на их сигнал, вы можете получить выгоду способами, которые вы не можете себе представить, например, решив, что поесть на обед или какое число в лотерею сыграть.
Неясно, поможет ли Манифест устранять ошибки, которые вы видите, не зная более подробностей.
Одним из распространенных способов использования манифестов является различное поведение кода в зависимости от статического типа коллекции. Например, что, если вы хотите обрабатывать List [String] иначе, чем другие типы List:
def foo[T](x: List[T])(implicit m: Manifest[T]) = {
if (m <:< manifest[String])
println("Hey, this list is full of strings")
else
println("Non-stringy list")
}
foo(List("one", "two")) // Hey, this list is full of strings
foo(List(1, 2)) // Non-stringy list
foo(List("one", 2)) // Non-stringy list
Решение на основе отражения, вероятно, будет включать проверку каждого элемента списка.
Ограничение контекста кажется наиболее подходящим для использования классов типов в scala и хорошо объяснено здесь Дебасишем Гошем: http://debasishg.blogspot.com/2010/06/scala-implicits-type-classes-here-i.html
Ограничения контекста также могут просто сделать сигнатуры методов более читабельными. Например, указанная выше функция может быть переписана с использованием таких контекстных границ:
def foo[T: Manifest](x: List[T]) = {
if (manifest[T] <:< manifest[String])
println("Hey, this list is full of strings")
else
println("Non-stringy list")
}
Не полный ответ, но относительно разницы между Manifest
и ClassManifest
вы можете найти пример в Scala 2.8 Array
paper :
Единственный оставшийся вопрос - как реализовать создание универсального массива. В отличие от Java, Scala позволяет создавать экземпляр нового
массива [T]
, гдеT
- параметр типа. Как это можно реализовать, учитывая тот факт, что в Java не существует унифицированного представления массива?Единственный способ сделать это - запросить дополнительную информацию времени выполнения, которая описывает тип
T
. В Scala 2.8 есть новый механизм для этого, который называется Manifest . Объект типаManifest [T]
предоставляет полную информацию о типеT
.
Значения манифеста
обычно передаются в неявных параметрах; и компилятор знает, как их построить для статически известных типовT
.Существует также более слабая форма с именем
ClassManifest
, которую можно построить, зная только класс верхнего уровня типа, без обязательного знания всех его типов аргументов .
Именно такая информация времени выполнения требуется для создания массива.
Пример:
Необходимо предоставить эту информацию, передав
ClassManifest [T]
в метод как неявный параметр:
def tabulate[T](len:Int, f:Int=>T)(implicit m:ClassManifest[T]) = {
val xs = new Array[T](len)
for (i <- 0 until len) xs(i) = f(i)
xs
}
В сокращенной форме контекстная граница1 может использоваться вместо параметра типа
T
,
(см. этот вопрос SO для иллюстрации )
, что дает:
def tabulate[T: ClassManifest](len:Int, f:Int=>T) = {
val xs = new Array[T](len)
for (i <- 0 until len) xs(i) = f(i)
xs
}
При вызове tabulate для такого типа, как
Int
, илиString
, илиList [T]
, компилятор Scala может создать манифест класса для передачи в качестве неявного аргумента для табуляции.