Обойти стирание типов в сопоставлении с образцом - PullRequest
6 голосов
/ 14 апреля 2011

Я пытаюсь обойти стирание типов при сопоставлении с образцом. Предполагая, что:

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 ]

4 голосов
/ 14 апреля 2011

Если вместо этого вы можете сделать 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
2 голосов
/ 14 апреля 2011

Ну, вопрос имеет своего рода неправильное предварительное условие (как я только что понял) - мы можем разделить 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.

...