Подтвердить что ты не робот

Абстрактные типы/параметры типа в Scala

Я пытаюсь написать код Scala, который должен сделать что-то вроде:

class Test[Type] { 
   def main {
       SomeFunc classOf[Type]
       val testVal: Type = new Type()
    }
 }

и он не работает. Я, очевидно, не понимаю ничего о Scala общих параметрах. Ясно, что недоразумение заключается в том, что в С++ шаблоны по существу функционируют подобно строковым подстановкам, поэтому новый тип() будет работать до тех пор, пока класс, передаваемый в него, имеет конструктор по умолчанию. Однако в Scala типы представляют собой разные типы объектов.

4b9b3361

Ответ 1

Как вы указываете, у С++ есть шаблоны. Короче говоря, С++ говорит, что "существует тест для всех типов T, чтобы Test компилировал". Это упрощает неявное добавление ограничений на T, но с нижней стороны они неявные и могут быть трудными для понимания пользователем вашего класса без чтения кода.

Scala параметрический полиморфизм (aka generics) работает намного больше, чем ML, Haskell, Java и С#. В Scala, когда вы пишете "class Test [T]", вы говорите "для всех T существует тип Test [T]" без ограничения. Это проще рассуждать о формально, но это означает, что вы должны быть откровенными в отношении ограничений. Например, в Scala вы можете сказать "class Test [T <: Foo]", чтобы сказать, что T должен быть подтипом Foo.

У С# есть способ добавить ограничение к T относительно конструкторов, но, к сожалению, Scala не делает.

Существует несколько способов решить вашу проблему в Scala. Один из них является типичным, но более подробным. Другой не является типичным.

Типичный способ выглядит как

class Test[T](implicit val factory : () => T) {
  val testVal = factory
}

Тогда у вас может быть множество фабрик для типов, полезных в вашей системе.

object Factories {
  implicit def listfact[X]() = List[X]()
  implicit def setfact[X]() = Set[X]()
  // etc
}

import Factories._
val t = new Test[Set[String]]

Если пользователям вашей библиотеки нужны собственные фабрики, они могут добавить свой собственный эквивалент объекта Factoryories. Одно из преимуществ этого решения заключается в том, что можно использовать что-либо с factory, независимо от того, существует или нет конструктор no-arg.

Не так называемый метод использует отражение и функцию в Scala, называемые манифестами, которые являются способом обойти ограничение Java относительно стирания типа

 class Test[T](implicit m : Manifest[T]) {
   val testVal = m.erasure.newInstance().asInstanceOf[T]
 }

В этой версии вы все еще пишете

class Foo
val t = new Test[Foo]

Однако, если нет конструктора no-arg, вы получаете исключение во время выполнения вместо ошибки статического типа

scala> new Test[Set[String]] 
java.lang.InstantiationException: scala.collection.immutable.Set
at java.lang.Class.newInstance0(Class.java:340)