2014-09-21 4 views
1

Мне нужно поддерживать несколько раскладок клавиатуры в моем приложении.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 
     } 
    } 
} 
+0

я думаю, что классы типа является то, что вам нужно (отредактирован мой ответ) – dk14

ответ

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 
+0

Точно, что я искал, спасибо! – Hamy

0

Почему бы не использовать вложенную карту? val keyLayouts = Map[Double, Map[String, KeyCode]], затем получите версию с keyLayouts.get(12).map(_.keys).getOrElse(//throw error or return default).

Не уверен, что я действительно понимаю вопрос.

Update:

Если вы хотите получить доступ к Key_Home как бы это где метод/значение, то вы должны сделать это так. Или вы могли бы использовать Symbol s, тогда вы могли бы сделать keyLayouts(12)('KEY_HOME).

Тем не менее, действительно не понимаю точку вопроса, хотя, также не понимаю, почему вы включили getKeycodes в свой фрагмент, поскольку он кажется несущественным.

+0

Я хотел бы избежать использовать что-нибудь вроде 'Map [String, KEYCODE]', а вместо иметь возможность возвращать объект с несколькими членами 'val KEY_FOO = KeyCode (xxx)'. Это означает, что все функции «KeyCode» проверяются во время компиляции, и вам не нужно постоянно проверять (так или иначе), если ваша карта содержит «KeyCode», например. 'keyMap.contains (« KEY_HOME »)' – Hamy

+0

В принципе, я бы хотел заменить 'keyLayouts.get (12) .map (_. keys) .getOrElse (// сбросить ошибку или вернуть значение по умолчанию)' с чем-то вроде 'keyLayouts .get (12) .KEY_HOME' – Hamy

+0

@Hamy ive обновлен, но ваш вопрос по-прежнему очень загадочен. – samthebest

0

Другой подход, который не был упомянут является scala.Dynamic чертой. Он позволяет вызывать произвольные методы для экземпляра типа, помеченного Dynamic, путем преобразования их в соответствующие applyDynamic, selectDynamic или updateDynamic вызов метода. Следующий пример демонстрирует возможное решение. Использование

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 
+0

нет никакой проверки времени компиляции без KEY_F00 в этом случае. Кроме того, нет никаких оснований хранить ключи в Set вместо Map (O (N) vs O (1)). selectDynamic (даже с Map) будет немного медленнее. – dk14

+0

, и если вы используете динамику - вам действительно не нужны имплициты (код может быть перезаписан без) и не нужны постоянные значения для версий, потому что по крайней мере ключевое извлечение фактически переходит в среду выполнения. Нет никакой разницы в использовании между динамическим KeyLayout [v12] .KEY_FOO и просто KeyLayout (12.0) («KEY_FOO»). – dk14

+0

@ dk14, согласовано. Это просто пример использования Dynamic. Мое намерение состояло в том, чтобы показать другой подход. – 4e6

Смежные вопросы