Reputation: 67280
I am trying to work around a type erasure in pattern matching. Assuming:
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] }
How can I get this to compile without warning and without asInstanceOf
:
def test[V](os: OutputStream, v: V): Unit = v match {
case hs: HasSerializer[V] => hs.serializer.save(os, v)
case _ => ???
}
? test
is called with a value from a map and there is no means to provide a class manifest.
Any fancy extractor trick maybe?
Upvotes: 6
Views: 617
Reputation: 67280
Well the question has kind of a wrong precondition (as I just realize) -- we can take Serializer
apart into a serializer and a deserializer. Obviously, when I have an instance of V
, my use case is serialization, and that doesn't require V
as a return type. Thus
trait Serializer { def save(os: OutputStream): Unit }
would suffice, and any type can mix that in. And do:
def testSer[V](os: OutputStream, v: V): Unit = v match {
case s: Serializer => s.save(os)
case _ => new ObjectOutputStream(os).writeObject(v)
}
And for deserialization, we would either provide the deserializer along with the construction of a Ref[V]
, or rely on class lookup through ObjectInputStream
.
Upvotes: 2
Reputation: 7979
If you can make Serializer an abstract class instead, you can give it a Manifest as an implicit constructor parameter, and use that to get the concrete class at construction, then use it later for dynamic type checks.
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
Upvotes: 4