2011-04-14 55 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