Какие механизмы есть у Scala для обобщений и подстановочных знаков по сравнению с Java? - PullRequest
3 голосов
/ 18 января 2012

Я часто раздвигаю границы системы типов Java, используя Guice, TypeLiteral, дженерики и шаблоны.Я часто сталкиваюсь с ситуациями, когда мне нужно выполнить непроверенные приведения, что в значительной степени нарушает безопасность типов - другими словами, «Generics Hell».

Вот упрощенный пример некоторых моих проблемных кодов Java.

class SquareDrawer implements ShapeDrawer<Row<Square>> {}
class Client {
   Key<SquareDrawer> SQUARE_DRAWER_KEY = 
      Key.get(SquareDrawer.class, randomAnnotation());
   void bindShapeDrawer(
      Key<? extends ShapeDrawer<Row<? extends Shape>>> shapeDrawer) {}

   Client() {
      // Note Unchecked cast required below
      bindShapeDrawer( 
         (Key<? extends ShapeDrawer<Row<? extends Shape>>>) SQUARE_DRAWER_KEY);
   }
}

Я изучал Scala и у меня сложилось впечатление (или иллюзия), что он лучше поддерживает дженерики, чем Java.Может ли приведенный выше код быть написан на Scala, чтобы избежать непроверенных приведений?

По-прежнему ли нужна TypeLiteral Guice в Scala?

Ответы [ 3 ]

3 голосов
/ 18 января 2012

Scala предлагает несколько вещей.

  • Типы с более высоким родом (я надеюсь, что я правильно использую этот термин) позволяют вам определять такие вещи, как «любой тип, имеющий другой тип в качестве параметра типа». Afaik нет способа выразить это в java

  • Параметры типа Co и Contravariant. В Java вы можете задать параметры одного или другого, используя подстановочные знаки в каждом месте, где они используются. В Scala вы просто объявляете их таковыми.

  • Свидетели типа (опять же: это правильный термин?) - это неявные функции, которые демонстрируют некоторое свойство аргументов типа, тем самым определяя ограничения на тип. Если существует неявное преобразование, соответствующее объявлению свидетеля, вызов скомпилирует выполненное условие.

  • Типы, зависящие от пути. Вы можете иметь типы, которые являются элементами экземпляров, поэтому каждый экземпляр имеет свой собственный тип. Опять же, вы не можете сделать это в java afaik.

2 голосов
/ 18 января 2012

Следующий (надеюсь) эквивалентный код Scala компилируется без ошибок.Может быть, мне нужно заявить, что он не содержит динамических приведений.Обратите внимание, что я должен был сделать Key ковариантным в качестве аргумента типа, потому что SquareDrawer является только подтипом ShapeDrawer[Row[Square]].

trait ShapeDrawer[A]
trait Row[A]
trait Shape
trait Square extends Shape
trait Key[+A]

//your code starts here
trait SquareDrawer extends ShapeDrawer[Row[Square]]

class Client{
  val SDK = new Key[SquareDrawer]{}

  bindShapeDrawer(SDK)

  def bindShapeDrawer[SD[A] <: ShapeDrawer[A],S <: Shape](shapeDrawer: Key[SD[Row[S]]]) {}
}
2 голосов
/ 18 января 2012

Scala имеет форму усовершенствованных типов , называемых манифестами.Они позволяют вам делать вещи, которые были бы довольно неуклюжими в Java из-за стирания типов.Все о них можно прочитать здесь: http://www.scala -blogs.org / 2008/10 / manifest-reified-types.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...