在模式匹配中绕过类型擦除

时间:2011-04-14 16:35:17

标签: scala pattern-matching type-erasure

我正在尝试在模式匹配中解决类型擦除问题。假设:

import java.io._

trait Serializer[V] {
  def save(os: OutputStream, v: V): Unit
  def load(in: InputStream): V
}

trait HasSerializer[V] { def serializer: Serializer[V] }

如何在没有警告且没有asInstanceOf的情况下进行编译:

def test[V](os: OutputStream, v: V): Unit = v match {
  case hs: HasSerializer[V] => hs.serializer.save(os, v)
  case _                    => ???
}

?使用地图中的值调用test,并且无法提供类清单。

任何花哨的提取器技巧都可能?

2 个答案:

答案 0 :(得分:4)

如果你可以使Serializer成为一个抽象类,你可以给它一个Manifest作为一个隐式的构造函数参数,并使用它来构造具体的类,然后再用它来进行动态类型检查。

import java.io._

abstract class Serializer[V: Manifest] {
  def save(os: OutputStream, v: V): Unit
  def load(in: InputStream): V
  val clazz = manifest[V].erasure
}

val ser = new Serializer[Int] {
  def save(os: OutputStream, v: Int) {
    os.write((v.toString + "\n").getBytes)
  }

  def load(in: InputStream) = {
    val line = new BufferedReader(new InputStreamReader(in)).readLine()
    line.toInt
  }
}

ser.clazz //  java.lang.Class[_] = int

答案 1 :(得分:2)

这个问题有一个错误的前提条件(正如我刚才所知) - 我们可以将Serializer分成一个序列化器和一个解串器。显然,当我有V的实例时,我的用例是序列化,并且不需要V作为返回类型。因此

trait Serializer { def save(os: OutputStream): Unit }

就足够了,任何类型都可以混合使用。并且可以:

def testSer[V](os: OutputStream, v: V): Unit = v match {
  case s: Serializer => s.save(os)
  case _ => new ObjectOutputStream(os).writeObject(v)
}

对于反序列化,我们要么提供反序列化器以及构造Ref[V],要么依赖于ObjectInputStream的类查找。