【问题标题】:Why can't I implement this Java interface in Scala without ugly anonymous classes为什么我不能在没有丑陋的匿名类的情况下在 Scala 中实现这个 Java 接口
【发布时间】:2016-02-01 11:28:33
【问题描述】:

我在Java中有以下接口

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

    Collection<T> getAllowedValues();

    Class<T> getValueClass();

    String getName(T value);
}

并试图在 scala 中实现它,但无法让它工作


第一次尝试:

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
}

编译时出错:类型参数 [T#Value] 不符合 trait IProperty 的类型参数边界 [T <: comparable>


最后我想出了一个办法,但对我来说它看起来很丑:

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#Value 不一样?
  4. 为什么编译器会抱怨 T#Value 与 Comparable[T] 不匹配,因为 Value extends Ordered[Value] 扩展了 Comparable[Value]?

【问题讨论】:

  • 为什么不class EnumerationProperty1[T &lt;: Enumeration](val enum: T, val name: String) extends IProperty[T] 。我不明白它是如何不足的。

标签: scala scala-java-interop


【解决方案1】:

啊,使用路径依赖类型的乐趣 ...

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-ish:

// 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 依赖于路径和巫术与 # 完成有关;)

【讨论】:

  • 我认为 4:Comparable[Value] 不是 Comparable[Enumeration#Value]。它为equals 保留了一个明确的外部指针;你可以想象compareTo(Enum#Value) 按枚举类名排序,然后按值序数或类似的怪异。 #2 即类参数的范围。
猜你喜欢
  • 2013-06-09
  • 1970-01-01
  • 2014-11-14
  • 2020-08-18
  • 1970-01-01
  • 2016-01-19
  • 2019-07-15
  • 2021-01-14
相关资源
最近更新 更多