2016-02-01 3 views
3

У меня есть следующий интерфейс в JavaПочему я не могу реализовать этот интерфейс Java в Scala без уродливых анонимных классов

public interface IProperty<T extends Comparable<T>> { 
    String getName(); 

    Collection<T> getAllowedValues(); 

    Class<T> getValueClass(); 

    String getName(T value); 
} 

и пытается осуществить его в Скале, но не может заставить его работать


Первая попытка:

class EnumerationProperty1[T <: Enumeration](val enum: T, val name: String) extends IProperty[enum.Value] { 
    override def getName = name 
    override def getValueClass = classOf[enum.Value] 
    override def getName(value: enum.Value): String = value.toString 
    override def getAllowedValues: java.util.Collection[enum.Value] = enum.values.toList 
} 

не компилируется с ошибкой: не найдено: значение перечисления


Вторая попытка:

class EnumerationProperty2[T <: Enumeration](val enum: T, val name: String) extends IProperty[T#Value] { 
    override def getName = name 
    override def getValueClass = classOf[T#Value] 
    override def getName(value: T#Value): String = value.toString 
    override def getAllowedValues: java.util.Collection[T#Value] = enum.values.toList 
} 

Не компилировать с Error: аргументы типа [T # значение] не соответствуют Черта границ параметров типа IProperty в [T <: Сопоставимые [T]]


Наконец я придумал, как сделать это, но это выглядит довольно некрасиво мне:

object EnumerationPropertyAnonymous { 
    def create[T <: Enumeration](enum: T, name: String) = { 
    new IProperty[enum.Value] { 
     override def getName = name 
     override def getValueClass = classOf[enum.Value] 
     override def getName(value: enum.Value): String = value.toString 
     override def getAllowedValues: java.util.Collection[enum.Value] = enum.values.toList 
    } 
    } 
} 

Вопросы:

  1. Что такое правильный способ сделать это?
  2. Почему enum.Value не работает с моей первой попытки, но работает, когда используется в анонимном классе?
  3. Почему переменная enum.Value и T # не совпадают?
  4. Почему компилятор жалуется на T # Значение не соответствует Comparable [T], так как Value расширяет упорядоченное [Value], которое расширяет Comparable [Value]?
+0

Почему бы не 'class EnumerationProperty1 [T <: Enumeration] (val enum: T, val name: String) extends IProperty [T] '. Я не вижу, как он падает. – Jatin

ответ

3

Ах, радости работы с зависимыми путем типами ...

Enumeration#Value является зависимым типом пути. Фактический тип Value зависит от текущего экземпляра реализации Enumeration.

Таким образом, если у вас есть два Enumerations как

object A extends Enumeration { 
    val first = Value(0, "first") 
} 

object B extends Enumeration { 
    val first = Value(0, "first") 
} 

следующие условия возврата false.

A.first == B.first 
A.first.isInstanceOf[B.first.type] 

, но это верно

A.first.isInstanceOf[Enumeration#Value] 

Более подробную информацию о пути зависимых типов, обратитесь к этому article

На вопросы:

@ 1), что зависит от того, вы пытаетесь выполнить. Быстрый способ сделать это будет с завода.Несколько похоже на ваш «анонимный», например, но немного больше Scala-иш:

// it is recommended to use converters instead of conversions. 
import scala.collection.JavaConverters._ 

case class EnumPropertyFactory[T <: Enumeration](val enum: T) { 
    def apply(name: String) = new EnumerationProperty(name) 

    class EnumerationProperty(val name: String) extends IProperty[enum.Value] { 
    override def getName = name 
    override def getValueClass = classOf[enum.Value] 
    override def getName(value: enum.Value): String = value.toString 
    override def getAllowedValues: java.util.Collection[enum.Value] = enum.values.toList.asJavaCollection 
    } 
} 

// can be used with something like 
val enum1PropertyFactory = EnumPropertyFactory(EnumOne) 
val foo = enum1PropertyFactory("foo") 
val bar = enum1PropertyFactory("bar") 

@ 2) Потому что в первом примере перечисление является параметром конструктора и во втором примере, это локальный val. Помните, что определение класса будет выглядеть в Java:

class EnumerationProperty1<T extends Enumeration> extends IProperty<enum.Value> { 
    public EnumerationProperty1(T enum, String name) { ... } 
} 

Здесь понятно, почему enum не может быть известно до того, как конструктор был вызван.

@ 3) см выше: зависимые пути типа

@ 4) Боюсь, что немного выше меня. Но я бы поспорил, что это связано с Enumeration#Value, зависящим от пути, и voodoo сделано с #;)

+0

Я думаю, 4: 'Сопоставимый [Значение]' не является 'Сопоставимым [Перечисление # Значение]'. Он хранит явный внешний указатель для целей 'equals'; вы можете представить себе 'compareTo (Enum # Value)' сортировка по имени класса enum, затем значение ordinal или аналогичная странность. # 2, то есть область действия класса param. –

Смежные вопросы