【问题标题】:Mixin in a trait parameterized with Enumeration into Enumeration将使用枚举参数化的特征中的混入到枚举中
【发布时间】:2014-07-09 02:30:04
【问题描述】:

我正在尝试将函数 apply 添加到我的 Enumerations。我想将枚举值映射到函数,然后像这样使用它:

Action(DO_THIS, "Arg string")

应该打印它的值。我有多个枚举类,我试图通过一个 trait mixin 来实现这个功能。到目前为止,我未能让编译器满意。我有这段代码无法编译:

trait EnumFunc [EnumType <: Enumeration] {
  protected def funcMappings: Map[EnumType#Value, Function1[String, Unit]]

  def apply(enum: EnumType#Value, arg: String): Unit =
    funcMappings.getOrElse(enum, (arg: String) => ())(arg)
}


trait Action extends Enumeration with EnumFunc[Action] {
  type Action = Value

  val DO_THIS, DO_THAT = Value

  override val funcMappings: Map[Action, Function1[String, Unit]] =
    Map(DO_THIS -> ((arg: String) => println(arg)))
}

object Action extends Action

编译器产生这个错误:

error: overriding method funcMappings in trait EnumFunc of type => Map[Action#Value,String => Unit];
 value funcMappings has incompatible type
         override val funcMappings: Map[Action, Function1[String, Unit]] =

我无法弄清楚到底是什么问题。有人可以解释一下是否有可能实现这一点以及为什么这不能编译?

【问题讨论】:

    标签: scala enumeration


    【解决方案1】:

    ActionEnumType#Value 内部的Value 并不完全相同。 Action 内部的Value 是路径依赖类型,它只能引用以this 为父对象的Values 实例,即Valuethis.Value 的同义词。 EnumType#Value 是一个类型投影,它可以引用 EnumType 实例中的任何值,而不关心它的父对象是什么。所以Action中的funcMappingsapply的声明实际上被赋予了更严格的参数类型,这不是类型安全的。

    不过,EnumType 上的类型参数实际上并不需要,如果你扩展Enumeration 可以直接使用Value

    trait EnumFunc extends Enumeration {
      protected def funcMappings: Map[Value, Function1[String, Unit]]
    
      def apply(enum: Value, arg: String): Unit =
        funcMappings.getOrElse(enum, (arg: String) => ())(arg)
    }
    

    然后它就会工作。然而,这只是 Scala 的 Enumeration 令人憎恶的众多例子之一。一旦您知道要为单个元素添加方法,最好使用案例类/对象的层次结构:

    abstract class Doers {
      def apply(s: String): Unit
    }
    case object DoThis extends Doers {
      def apply(s: String): Unit = println(s)
    }
    case object DoThat extends Doers {
      def apply(s: String): Unit = ???
    }
    

    【讨论】:

    • 感谢它的工作,确实枚举是一种痛苦,但我必须使用它,因为我使用的第三方库需要枚举值。我对类型的限制太大,但据我了解,您的解决方案有效,因为类型擦除,其中所有 Value 实例都变得相同,它们不会“记住”封闭类类型。
    • 我意识到我对为什么你的代码不起作用的解释不正确,我已经编辑了我的答案。 Enumeration 实际上依赖于路径相关类型,因此即使类型擦除也应该是安全的。
    猜你喜欢
    • 1970-01-01
    • 2015-06-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-22
    相关资源
    最近更新 更多