Что такое Декларация в Scala и когда Вам нужна она?

Начиная с Scala 2.7.2 существует что-то позвонившее Manifest который является обходным решением для стирания типа Java. Но как делает Manifest работайте точно и почему / когда необходимо будет использовать его?

Декларации сообщения в блоге: Овеществленные Типы Jorge Ortiz объясняют часть его, но это не объясняет, как использовать его вместе с границами контекста.

Кроме того, что ClassManifest, с чем различие Manifest?

У меня есть некоторый код (часть большей программы, не может легко включать его здесь), который имеет некоторые предупреждения относительно стирания типа; я подозреваю, что могу решить их при помощи деклараций, но я не уверен точно как.

130
задан Community 23 May 2017 в 12:10
поделиться

2 ответа

Компилятор знает больше информации о типах, чем среда выполнения 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")
  }
195
ответ дан 24 November 2019 в 00:24
поделиться

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

25
ответ дан 24 November 2019 в 00:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: