引用方法签名中的枚举值类型

时间:2010-03-02 16:04:14

标签: scala enumeration

我想为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方法中删除返回类型声明,但这给了我一个“非法的依赖方法类型”。这给我留下了很多问题:

  1. 这可以指定吗?无论如何,我想从String中解析枚举字段时得到一个很好的错误消息。

  2. 为什么我会获得“非法依赖方法类型”?

  3. 在这种情况下,“#”运算符(?)究竟是什么?

1 个答案:

答案 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

我们TEnumeration的子类,enumT的一个实例,而且 - 因为无法表达Value {1}}必须来自 T的特定实例,我们必须诉诸T#Value(即T的内部类型,而不考虑哪个特别是T它来自)。

现在我们必须传入一个特定的对象,取回一个通用的内部对象,并在ExampleObject.type#ValueExampleObject.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的类{将此OutermyOuter的实例作为其封闭类“。另外,我没有在2.8.0 Beta1中获得依赖类型错误 - 但是无法指定类型会使事情变得非常尴尬。


编辑:更新错误报告 - 它现在的工作方式显然是故意的。要以这种方式使用类型,您应该在函数调用中明确指定类型(因为它不是您想要的),如此

val suggested: SampleEnum.type#Value = parse[SampleEnum.type]("include",SampleEnum)

如果您只需要执行此操作几次,这种方式会更容易。如果你必须多次这样做,用val(或lazy val)实例化创建你自己的类可能会使事情变得更容易/更紧凑。