2015-10-27 2 views
0

У меня есть два класса с некоторыми членами данных, как это:Scala, как восстановить тип дженерик в Еогеаспе

class MyInfo { 
    private val myId: String 
    private val time: DateTime 
    private val solution: Long 
    private val banner: Int 
} 

Class HisInfo { 
    private val id: String 
    private val solution: Long 
    private val banner: Int 
} 

Как вы можете видеть, что эти два класса разделяет два члена, и в моем реальном проекте они разделяют больше. Мне нужно, чтобы сохранить их в HBase и разработал класс вроде этого:

sealed trait Element[T] { 
    def serialize(value: T)(implicit val helper: Helper[T]): Array[Byte] 
    def deserialize(bytes: Array[Byte])(implicit val helper: Helper[T]): T 
} 

case object LongElement extends Element[Long] {...} 
case object IntElement extends Element[Int] {...} 

class Info { 
protected val data: Map[Element[_], Any] = new mutable.Map[Element[_], Any]() 
} 

class MyInfo extends Info { 
    val elements = List(LongElement, IntLement) 
    def saveToHBase = { 
    elements.foreach { e => 
    val v = e.serialize(data(e)) 
    // do sth with v 
    } 
    } 

На самом деле я определил реализацию Helper [Int] и Helper [Long], но компилятор жалуется, что не может найти неявное значение параметр Помощник [_1]. Может кто-нибудь помочь мне в разработке этих классов?

+0

Определили ты ' Помощник [Int] и 'Помощник [Long]' как неявные значения, доступные в области, где вы называете 'e.serialize'? –

+0

Существует ли бесконечно уникальное общее поле каждого типа с соответствующим «Помощником» или нужна дополнительная идентификация по имени? – Odomontois

ответ

0

Фактически я определил реализации Helper [Int] и Helper [Long], но компилятор жалуется, что не может найти неявное значение для параметра Helper [_1].

Ну, что произойдет, если elementsElement[String] включал (или какой-либо другой тип, для которого у вас нет неявного Helper). Учитывая тип elements, компилятор не может этого знать.

Я думаю, что если вам нужен Helper для всех методов Element в любом случае, вы должны просто сделать его частью типа:

sealed trait Element[T] { 
    val helper: Helper[T] // or def if you want to put it in the companion object 
    def serialize(value: T): Array[Byte] 
    def deserialize(bytes: Array[Byte]): T 
} 

или

sealed abstract class Element[T](implicit val helper: Helper[T]) { 
    def serialize(value: T): Array[Byte] 
    def deserialize(bytes: Array[Byte]): T 
} 

По крайней мере, в большинстве случаев ,

+0

Спасибо за ответ, и это действительно помогает. –

0

Это определенно выглядит как работа для shapeless
крутой вещи о бесформенном, он может конвертировать свой класс в список как структура под названием HList.
Обычные коллекции Scala, такие как List, должны содержать информацию об элементах, чтобы привести их к общему типу.
HList может сохранить тип каждого элемента, обеспечивая при этом List -like функциональность

Позволяет определить тип с их общими полями в отдельный тип

import org.joda.time.DateTime 

class Common(
       val solution: Long, 
       val banner: Int 
      ) 

class MyInfo(
       myId: String, 
       time: DateTime, 
       solution: Long, 
       banner: Int 
      ) extends Common(solution, banner) 

class HistInfo(
       id: String, 
       solution: Long, 
       banner: Int 
      ) extends Common(solution, banner) 

Теперь давайте определим что-то выглядит как серийности:

trait Helper[T] extends (T => Array[Byte]) 

implicit object longHelper extends Helper[Long] { 
    def apply(x: Long) = 0 to 7 map (i => (x >> (i * 8)).toByte) toArray 
} 

implicit object intHelper extends Helper[Int] { 
    def apply(x: Int) = 0 to 3 map (i => (x >> (i * 8)).toByte) toArray 
} 

Теперь что-то интересное. Мы создадим специальный объект, который может превратить ваш Common тип специальной HList, который содержит все значения, сохраняющие его типа информации и статический сохраненную строку с именем поля:

import shapeless._ 
val lgen = LabelledGeneric[Common] 

Далее мы определим специальную функцию, как вещь, чтобы отобразить более таких как HList.Было бы найти известный implicit Helper и связать его результат с соответствующим именем поля:

import shapeless.labelled.FieldType 

object serialized extends Poly1 { 
    implicit def serialize[K <: Symbol, T] 
    (implicit helper: Helper[T], key: Witness.Aux[K]) 
    = at[FieldType[K, T]](field => key.value.name -> helper(field)) 
} 

Теперь мы определим некоторые пользователь этой функции:

def extractMap(x: Common): Map[String, Seq[Byte]] = 
    lgen.to(histInfo).map(serialized).toList.toMap.mapValues(_.toSeq) 

Вы могли бы проверить вас работает функция:

val histInfo = new HistInfo("123", 12, 3) 
println(extractMap(histInfo)) 

будет распечатать

Карта (решение -> WrappedArray (12, 0, 0, 0, 0, 0, 0, 0), баннер -> WrappedArray (3, 0, 0, 0))

+0

Спасибо, но решение кажется сложным, и я предполагаю, что он использует много отражений, что может значительно повредить производительность. –

+0

@ Liu Renjie No. Он вообще не использует отражение. Безшовная построена на макросах + проблемы – Odomontois

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