Scala如何在foreach中恢复泛型类型

时间:2015-10-27 08:22:48

标签: scala generics

我有两个类,其中包含一些数据成员:

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]的实现,但是编译器抱怨它找不到参数Helper [_1]的隐含值。有人可以帮我设计这些课程吗?

2 个答案:

答案 0 :(得分:0)

  

实际上我已经定义了Helper [Int]和Helper [Long]的实现,但是编译器抱怨它找不到参数Helper [_1]的隐含值。

好吧,考虑如果elements包含Element[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
}

至少在大多数情况下。

答案 1 :(得分:0)

对于shapeless来说,这看起来很像。{ 关于无形的很酷的事情,它可以将你的类转换为名为HList的结构列表 像List这样的Scala普通集合应该删除有关元素的信息,以使它们成为普通类型 HList可以保存每个元素的类型,同时提供List - 类似功能

让我们用单独的类型

中的公共字段来定义您的类型
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))

将打印

  

地图(解决方案 - &gt; WrappedArray(12,0,0,0,0,0,0,0),横幅 - &gt;   WrappedArray(3,0,0,0))