Scala将成员添加到基类

时间:2014-09-21 01:23:08

标签: scala

我需要在我的应用程序中支持多种键盘布局。

这是一个解决方案,但在Scala中我怀疑有更好的方法可以让我直接使用KeyLayout个变量,例如输入KeyLayout.KEY_HOME而不是get_keycodes(12)("KEY_HOME") 。这可能吗?如果我像下面的代码一样使用Map,那么我的其他代码必须经常检查我想要使用的每个密钥代码是否实际存在,代码如get_keycodes(12).contains("KEY_HOME")。如果get_keycodes(12)返回一个包含多个val KEY_FOO = KeyCode(x)项的对象会好得多,这样你就可以做get_keycodes(12).KEY_HOME这样的事情并让编译器确保这个工作正常工作

case class KeyCode(key: Int)

object `KeyLayout_v12` extends KeyLayout {
  val keys = Map("KEY_HOME" -> KeyCode(0x007a))
}

object `KeyLayout_v15.2` extends KeyLayout {
  val keys = Map("KEY_HOME" -> KeyCode(0x003a))
}

class KeyLayout

object KeyLayout {

  // Gets the default keycodes for version you are using
  def getKeycodes(version: Double): Map[String, KeyLayout] = androidVersion match {
      case 12 => `KeyLayout_v12`.keys
      case 15.2 => `KeyLayout_v15.2`.keys
      case _ => {
        info(s"Unknown $version, returning keycodes for 12")
        `KeyLayout_v12`.keys
      }
    }
}

3 个答案:

答案 0 :(得分:3)

您可以使用类型类(无论如何您应该在编译时知道或假设androidVesion):

trait Version
object v12 extends Version
object v15_2 extends Version

class Layout[T <: Version]

implicit class v12layout(v: Layout[v12.type]) {    
        val KEY_HOME = 100500
}

implicit class v15_2layout(v: Layout[v15_2.type]) {
        val KEY_HOME = 100600
        val KEY_A = 300900
}

def getLayout[T <: Version](v: T) = new Layout[T]

getLayout(v15_2).KEY_HOME

用法:

scala> getLayout(v12).KEY_HOME
res4: Int = 100500

scala> getLayout(v15_2).KEY_HOME
res5: Int = 100600

scala> getLayout(v12).KEY_A
<console>:20: error: value KEY_A is not a member of Layout[v12.type]
          getLayout(v12).KEY_A
                         ^

scala> getLayout(v15_2).KEY_A
res7: Int = 300900

答案 1 :(得分:0)

为什么不使用嵌套Map? val keyLayouts = Map[Double, Map[String, KeyCode]],然后获得keyLayouts.get(12).map(_.keys).getOrElse(//throw error or return default)的版本。

不确定我是否真的理解这个问题。

更新

如果你想要访问KEY_HOME,就好像它是一个方法/值,那么你必须这样做。或者你可以使用Symbol s,然后你就可以keyLayouts(12)('KEY_HOME)

虽然仍然不明白这个问题的重点,也不明白为什么你将getKeycodes包含在你的代码段中,因为它似乎无关紧要。

答案 2 :(得分:0)

另一种未提及的方法是scala.Dynamic特征。它允许在标记为Dynamic的类型的实例上调用任意方法,方法是将它们转换为适当的applyDynamicselectDynamicupdateDynamic方法调用。以下示例演示了可能的解决方案。

case class Key(name: String, code: Int)

sealed trait Version
sealed trait v12 extends Version
sealed trait v15_2 extends Version

sealed trait KeyLayout[T <: Version] extends Dynamic {

  def keys: Set[Key]

  def selectDynamic(name: String): Option[Key] =
    keys.find(_.name == name)
}

object KeyLayout {

  def apply[V <: Version: KeyLayout] = implicitly[KeyLayout[V]]

  implicit object `12` extends KeyLayout[v12] {
    val keys = Set(Key("KEY_HOME", 0x007a))
  }

  implicit object `15_2` extends KeyLayout[v15_2] {
    val keys = Set(Key("KEY_HOME", 0x003a))
  }
}

使用示例:

scala> KeyLayout[v15_2].KEY_HOME
res2: Option[Key] = Some(Key(KEY_HOME,58))

scala> KeyLayout[v12].KEY_FOO
res3: Option[Key] = None