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

Ada*_*ung 4 enumeration scala

我想为scala.Enumeration添加一个方法.我的第一个方法是试图扩展它,但被这个咬了.我的第二种方法是尝试定义一个方法,并传入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)
  }
}
Run Code Online (Sandbox Code Playgroud)

一个明显的解决方法是从parse方法中删除返回类型声明,但这给了我一个"非法的依赖方法类型".这给我留下了很多问题:

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

  2. 为什么我会得到"非法依赖方法类型"?

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

Rex*_*err 5

这看起来像是一个错误(至少在我测试过的2.8.0 Beta1中).

特别有启发性的是:

scala> var x: SampleEnum.type#Value = null
x: SampleEnum.Value = null
Run Code Online (Sandbox Code Playgroud)

在这里,我们要求任意内部类型,但我们实际上得到了特定的内部类型.这已经坏了(如果没有错误报告,我将提交错误报告,除非其他人迅速解释为什么这不是一个错误).

那么该怎么办?好吧,首先,让我们理解解析的原始方法签名:

def parse[T <: Enumeration](name:String, enum:T):T#Value
Run Code Online (Sandbox Code Playgroud)

我们T这的一个子类Enumeration,enum这是一个实例T,并且-因为没有办法表达的是,Value必须从该特定实例T,我们不得不求助于T#Value(即内型的T,而不关心哪些特别是T它来自).

现在我们必须传入一个特定的对象,获取一个通用的内部对象,即使它们的输入方式不同ExampleObject.type#Value,ExampleObject.Value也要面对相同的内部对象.

所以我们必须从头开始编写自己的对象:

class SampleWorkaroundClass extends Enumeration {
  val include, exclude = Value
}
lazy val SampleWorkaround = new SampleWorkaroundClass
Run Code Online (Sandbox Code Playgroud)

这里我们有一个特殊定义类的单个实例.现在我们可以解决这个问题Object:

scala> val typeWorks:SampleWorkaroundClass#Value = parse("include",SampleWorkaround)
typeWorks: SampleWorkaroundClass#Value = include
Run Code Online (Sandbox Code Playgroud)

(这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)
Run Code Online (Sandbox Code Playgroud)

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