4

我有一个像这样的简单枚举:

object ConditionOperator extends Enumeration {

  val Equal           = Value("equal")
  val NotEqual        = Value("notEqual")
  val GreaterOrEqual  = Value("greaterOrEqual")
  val Greater         = Value("greater")
  val LessOrEqual     = Value("lessOrEqual")
  val Less            = Value("less")

我想为每个枚举添加一个方法,以便我可以像这样使用它:

def buildSqlCondition(field: String, operator: ConditionOperator.Value, value: String ) = {
  val sqlOperator = operator.toSql
  [...]

所以,ConditionOperator.Equal.toSql 会返回“=”,而 ConditionOperator.NotEqual.toSql 会返回“<>”,等等......

但我不知道如何定义 toSql 方法,以便每个枚举都可以“看到”它自己的值并决定如何将自己转换为 sql 运算符......

4

3 回答 3

7

这是我在过去对该主题的各种搜索中为 Scala 2.9.2 找到的示例:

object Progress extends Enumeration {
    type enum = Value

    val READY = new ProgressVal {
      val isActive = false
      def myMethod: Any = { .. }
    }

    val EXECUTE = new ProgressVal {
      val isActive = true
      def myMethod: Any = { .. }
    }

    val COMPLETE = new ProgressVal {
      val isActive = false
      def myMethod: Any = { .. }
    }

    protected abstract class ProgressVal extends Val() {
      val isActive: Boolean
      def myMethod: Any
    }
    implicit def valueToProgress(valu: Value) = valu.asInstanceOf[ProgressVal]
}
type Progress = Progress.enum
  • implicit是使其可用的关键。

  • 和有点多余type enumtype Progress我将它们包括在内是为了将这两个概念都介绍为我发现有帮助的东西。


为了给予应有的荣誉,最初的想法来自 Sean Ross在回答这个问题是重复的问题时

于 2012-09-10T05:37:34.337 回答
5

您可以从定义一个覆盖Enumeration.Val. 为简化起见,我们称它为(我们重载了定义Value的原意)。所以我们有了新的类型,它继承了它本身继承了。ValueEnumerationValueEnumeration.ValEnumeration.Value

鉴于它toSql没有副作用并为每个枚举返回不同的字符串,您不妨将其设为val.

最后,为了使其完全可用,您需要让 ConditionOperator.apply 和 ConditionOperator.withName 返回新定义的Value类,而不是. 否则,当使用 apply 或 withName 按索引/名称查找实例时,将无法调用 toSql,因为枚举类型不够具体。理想情况下,我们只想覆盖并添加强制转换,但这些方法是最终的。但是我们可以在这里使用一个小技巧:定义新方法 和ValueEnumerationConditionOperatorapplywithNameConditionOperator.ValueapplywithName具有相同的签名,但有一个始终可用的附加隐式参数(Predef.DummyImplicit 非常适合此卷)。附加参数确保签名不同,以便我们能够定义这些新方法,同时与原始的 apply/withName 方法几乎没有区别。scala 中重载解析的规则确保我们的新方法是编译器喜欢的方法(因此我们在实践中隐藏了原始方法)。

object ConditionOperator extends Enumeration {
  // Here we overload the meaning of "Value" to suit our needs
  class Value(name: String, val toSql: String) extends super.Val(name) {
    def someFlag: Boolean = true // An example of another method, that you can override below
  }
  val Equal           = new Value("equal", "=")
  val NotEqual        = new Value("notEqual", "<>")
  val GreaterOrEqual  = new Value("greaterOrEqual", ">=")
  val Greater         = new Value("greater", ">")
  val LessOrEqual     = new Value("lessOrEqual", "<=") { override def someFlag = false }
  val Less            = new Value("less", "<")  
  final def apply(x: Int)( implicit dummy: DummyImplicit ): Value = super.apply(x).asInstanceOf[Value]
  final def withName(s: String)( implicit dummy: DummyImplicit ): Value = super.withName(s).asInstanceOf[Value]
}

您可以检查您现在是否可以执行ConditionOperator(2).toSqlConditionOperator.withName("greaterOrEqual") 之类的操作,它们都按预期返回 ">="。最后,上面的体操可以抽象掉:

abstract class CustomEnumeration extends Enumeration {
  type BaseValue = super.Val
  type CustomValue <: super.Value
  type Value = CustomValue
  final def apply(x: Int)( implicit dummy: DummyImplicit ): CustomValue = super.apply(x).asInstanceOf[CustomValue]
  final def withName(s: String)( implicit dummy: DummyImplicit ): CustomValue = super.withName(s).asInstanceOf[CustomValue]
}
object ConditionOperator extends CustomEnumeration {
  class CustomValue(name: String, val toSql: String) extends BaseValue(name) {
    def someFlag: Boolean = true
  }
  val Equal           = new Value("equal", "=")
  val NotEqual        = new Value("notEqual", "<>")
  val GreaterOrEqual  = new Value("greaterOrEqual", ">=")
  val Greater         = new Value("greater", ">")
  val LessOrEqual     = new Value("lessOrEqual", "<=") { override def someFlag = false }
  val Less            = new Value("less", "<")  
}
于 2012-09-10T09:53:57.480 回答
1
object ConditionOperator extends Enumeration {

  implicit def overrideValue(v:Value) = new OverridedValue(v)
  class OverridedValue(val v:Value) {
    def toSql = v.toString
  }
  val Equal           = Value("=")
  val NotEqual        = Value("<>")
  val GreaterOrEqual  = Value(">=")
  val Greater         = Value(">")
  val LessOrEqual     = Value("<=")
  val Less            = Value("<")

}

import ConditionOperator._

assert(Equal.toSql == "=")

在 scala 2.10 中,您可以通过使用隐式类使其更简单,替换

implicit def overrideValue(v:Value) = new OverridedValue(v)
class OverridedValue(val v:Value) {
  def toSql = v.toString
}

implicit class OverridedValue(val v:Value) {
  def toSql = v.toString
}
于 2012-09-10T05:53:48.067 回答