为什么我不能在没有丑陋的匿名 类 的情况下在 Scala 中实现这个 Java 接口
Why can't I implement this Java interface in Scala without ugly anonymous classes
我在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] 不符合特征 IProperty 的类型参数范围 [T <: Comparable[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
}
}
}
问题:
- 正确的做法是什么?
- 为什么 enum.Value 在我第一次尝试时不起作用,但在匿名 class 中使用时却起作用?
- 为什么 enum.Value 和 T#Value 不一样?
- 为什么编译器抱怨 T#Value 不匹配 Comparable[T],因为 Value 扩展了 Ordered[Value] 而后者扩展了 Comparable[Value]?
啊,使用 路径依赖类型 的乐趣...
Enumeration#Value
是路径依赖类型。
也就是说 Value
的实际类型取决于 Enumeration
的当前实例的实现。
因此,如果您有两个 Enumerations
喜欢
object A extends Enumeration {
val first = Value(0, "first")
}
object B extends Enumeration {
val first = Value(0, "first")
}
以下条件returnfalse
.
A.first == B.first
A.first.isInstanceOf[B.first.type]
但这是真的
A.first.isInstanceOf[Enumeration#Value]
有关路径依赖类型的更多信息,请参阅此article
问题:
@1) 这取决于您要完成的任务。一个快速的方法是与工厂合作。有点类似于您的 'anonymous' 示例,但更像 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
。记住 class 定义在 java:
中的样子
class EnumerationProperty1<T extends Enumeration> extends IProperty<enum.Value> {
public EnumerationProperty1(T enum, String name) { ... }
}
这里就很清楚了,为什么enum
在调用构造函数之前无法知道
@3) 见上:路径依赖类型
@4) 恐怕有点过头了。但我敢打赌,这与 Enumeration#Value
依赖于路径以及 #
完成的伏都教有关 ;)
我在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] 不符合特征 IProperty 的类型参数范围 [T <: Comparable[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
}
}
}
问题:
- 正确的做法是什么?
- 为什么 enum.Value 在我第一次尝试时不起作用,但在匿名 class 中使用时却起作用?
- 为什么 enum.Value 和 T#Value 不一样?
- 为什么编译器抱怨 T#Value 不匹配 Comparable[T],因为 Value 扩展了 Ordered[Value] 而后者扩展了 Comparable[Value]?
啊,使用 路径依赖类型 的乐趣...
Enumeration#Value
是路径依赖类型。
也就是说 Value
的实际类型取决于 Enumeration
的当前实例的实现。
因此,如果您有两个 Enumerations
喜欢
object A extends Enumeration {
val first = Value(0, "first")
}
object B extends Enumeration {
val first = Value(0, "first")
}
以下条件returnfalse
.
A.first == B.first
A.first.isInstanceOf[B.first.type]
但这是真的
A.first.isInstanceOf[Enumeration#Value]
有关路径依赖类型的更多信息,请参阅此article
问题:
@1) 这取决于您要完成的任务。一个快速的方法是与工厂合作。有点类似于您的 'anonymous' 示例,但更像 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
。记住 class 定义在 java:
class EnumerationProperty1<T extends Enumeration> extends IProperty<enum.Value> {
public EnumerationProperty1(T enum, String name) { ... }
}
这里就很清楚了,为什么enum
在调用构造函数之前无法知道
@3) 见上:路径依赖类型
@4) 恐怕有点过头了。但我敢打赌,这与 Enumeration#Value
依赖于路径以及 #
完成的伏都教有关 ;)