Для библиотеки, над которой я работаю, мне нужен эффективный, удобный и типобезопасный метод сериализации классов scala. Идеальным было бы, если пользователь может создать класс case, и, пока все члены сериализуемы, это, похоже, тоже должно быть. Я точно знаю тип как на этапе сериализации, так и на стадии десериализации, поэтому нет необходимости (и я не могу себе этого позволить) иметь какую-либо информацию «схемы» как часть формата сериализации (например, сериализации Java-объекта).
Я играл с несколькими идеями, и эта, кажется, подошла довольно близко. Главная проблема, которую я вижу здесь, заключается в том, как пользователь должен указать функции класса «применять» и «не применять». Так как это действительно статические функции, мне интересно, можно ли заставить компилятор найти его.
Вот отдельный пример:
trait InOut[T] {
// just keeping things simple, for illustration purposes
def toWire(x: T): Array[Byte]
def fromWire(v: Array[Byte] ): T
}
object InOutConversions {
// Pretend these are implemented properly
implicit def Int = new InOut[Int] {
def toWire(x: Int): Array[Byte] = Array[Byte]()
def fromWire(v: Array[Byte] ): Int = 44
}
implicit def String = new InOut[String] {
def toWire(x: String): Array[Byte] = Array[Byte]()
def fromWire(v: Array[Byte] ): String = "blah"
}
// etc... for all the basic types
}
И тогда мне нужна такая функция:
def serialize2[T, A1 : InOut, A2 : InOut](unapply : T => Option[Product2[A1, A2]])(obj : T) : Array[Byte] = {
val product : Product2[A1, A2] = unapply(obj).get
implicitly[InOut[A1]].toWire(product._1) ++ implicitly[InOut[A2]].toWire(product._2)
}
Что позволит пользователю использовать его довольно легко. например,
case class Jesus(a: Int, b: String)
val j = Jesus(4, "Testing")
serialize2 (Jesus.unapply(_)) (j)
Но, как вы можете видеть, эта последняя строка была действительно противной. Конечно, должно быть возможно улучшить это? (Учитывая Иисуса, я определенно могу найти «неприменимый» статический метод)