2011-04-14 35 views
6

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

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

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

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

就足够了,任何类型可以混合在和Do:

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进行类查找。

+0

“任何类型都可以混合它”不是当然,这是真的。这个问题仍然适用于现有的类型,假设我们想为“Int”提供一个序列化程序(如Alex的例子)... – 2011-04-15 16:05:50

4

如果您可以将Serializer转换为抽象类,您可以将它作为隐式构造函数参数给它,然后使用它在构造时获取具体类,然后稍后将其用于动态类型检查。

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

但是,如何找出V的一个实例是否提供串行器?我仍然不知道如何在'test'方法中执行检查,而最终不必转换为'V'? – 2011-04-14 18:24:04

+0

如果你不能使用类型类,因为值本质上是无类型的,我不确定你可以避免有一些注册表和查找机制。我很高兴看到另一种方法! – 2011-04-14 19:02:09

+0

我不需要注册表,因为我可以匹配'HasSerializer [_]',然后安全地转换为'HasSerializer [V]',但这正是我不想做的。 'V'在不同的接口之间传递了几次,传递'ClassManifest'根本就没有选择,Scala只是诚实地吮吸着'reification'这个概念...... – 2011-04-14 19:22:23