我想为scala.Enumeration添加一个方法。我的第一种方法是尝试扩展它,但被this咬了。我的第二种方法是尝试定义一个方法,并传入Enumeration - 如果有效,我希望使用隐式转换。但是,我很难用方法的返回类型保留类型。
object EnumExample {
object SampleEnum extends Enumeration {
val include, exclude = Value
}
def parse[T <: Enumeration](name:String, enum:T):T#Value =
enum.valueOf(name) match {
case Some(x) => x
case x => throw new RuntimeException("No field named '" + name + "' found on enum " + enum + ", legal values = " + enum.values)
}
def main(args:Array[String]) = {
//compiles fine, and preserves custom type
val withNameExample:SampleEnum.Value = SampleEnum.withName("include")
//also fine, but we lost type info
val enumWithHash:Enumeration#Value = parse("include", SampleEnum)
/**
error: type mismatch;
found : Main.$anon.EnumExample.SampleEnum#Value
required: Main.$anon.EnumExample.SampleEnum.Value
val parseExample:SampleEnum.Value = parse("include", SampleEnum)
*
*/
val customTypeWithHash:SampleEnum.type#Value = parse("include", SampleEnum)
//same error
val customTypeWithDot:SampleEnum.Value = parse("include", SampleEnum)
}
}
一个明显的解决方法是从parse方法中删除返回类型声明,但这给了我一个“非法的依赖方法类型”。这给我留下了很多问题:
这可以指定吗?无论如何,我想从String中解析枚举字段时得到一个很好的错误消息。
为什么我会获得“非法依赖方法类型”?
在这种情况下,“#”运算符(?)究竟是什么?
答案 0 :(得分:5)
对我来说这看起来像个错误(至少在我测试过的2.8.0 Beta1中)。
特别有启发性的是:
scala> var x: SampleEnum.type#Value = null
x: SampleEnum.Value = null
在这里,我们要求任意内部类型,但实际上我们正在获取特定的内部类型。这已经坏了(如果没有错误报告,我将提交错误报告,除非其他人迅速解释为什么这不是错误)。
那么,该怎么办?好吧,首先,让我们理解解析的原始方法签名:
def parse[T <: Enumeration](name:String, enum:T):T#Value
我们T
是Enumeration
的子类,enum
是T
的一个实例,而且 - 因为无法表达Value
{1}}必须来自 T
的特定实例,我们必须诉诸T#Value
(即T
的内部类型,而不考虑哪个特别是T
它来自)。
现在我们必须传入一个特定的对象,取回一个通用的内部对象,并在ExampleObject.type#Value
与ExampleObject.Value
相同的情况下执行它,即使它们的输入方式不同。
所以我们必须从头开始编写自己的对象:
class SampleWorkaroundClass extends Enumeration {
val include, exclude = Value
}
lazy val SampleWorkaround = new SampleWorkaroundClass
这里我们有一个特别定义的类的单个实例。现在我们可以解决Object
中的错误:
scala> val typeWorks:SampleWorkaroundClass#Value = parse("include",SampleWorkaround)
typeWorks: SampleWorkaroundClass#Value = include
(lazy val
只是为了获得与未使用它们之前未实例化的对象完全相同的行为;但仅val
就可以了。)
编辑:Outer#Inner
表示“来自此外部类的任何类型Inner
的内部类”,而不是myOuter.Inner
,这意味着“只有类Inner
的类{将此Outer
,myOuter
的实例作为其封闭类“。另外,我没有在2.8.0 Beta1中获得依赖类型错误 - 但是无法指定类型会使事情变得非常尴尬。
编辑:更新错误报告 - 它现在的工作方式显然是故意的。要以这种方式使用类型,您应该在函数调用中明确指定类型(因为它不是您想要的),如此
val suggested: SampleEnum.type#Value = parse[SampleEnum.type]("include",SampleEnum)
如果您只需要执行此操作几次,这种方式会更容易。如果你必须多次这样做,用val(或lazy val)实例化创建你自己的类可能会使事情变得更容易/更紧凑。