Сериализация функций скалы - PullRequest
10 голосов
/ 19 марта 2012

Я знаю, что есть Jerkson и scalaxb и даже XStream Java, которые успешно способны сериализовать данные scala. Я знаю, что они хорошо справляются со строками, целыми числами и даже классами падежей. Но если у меня есть функция в качестве одного из полей?

например. если у меня есть что-то вроде:

case class Foo(bar: (Int) => Boolean, baz: Int) 

Могут ли эти поля быть каким-либо образом сериализованы в JSON или XML (на самом деле, мне все равно, какие из них должны быть удобочитаемыми для человека, поэтому я не хочу использовать SBinary )?

EDIT

Зачем мне это делать? Прямо сейчас я пишу реализацию дерева решений. Я не хочу восстанавливать эти деревья каждый раз из обучающих данных, поэтому мне нужно их сериализовать, и эту часть можно выполнить с помощью SBinary. Но кроме того, было бы неплохо, если бы мы, люди, могли взглянуть на сериализованное дерево и проанализировать его.

Это не такая широкая задача, как я написал в заголовке, да. Сейчас я думаю о том, чтобы написать собственный сериализатор (например, для Джерксона) с моим собственным форматом или записать в строковое поле, а затем проанализировать это обратно.

Но я подумал, что может быть какой-то безумно лучший способ сделать это.

Ответы [ 3 ]

12 голосов
/ 29 апреля 2016

Да. Это возможно и только что взорвало мой разум:

import java.io._

def write[A](obj: A): Array[Byte] = {
  val bo = new ByteArrayOutputStream()
  new ObjectOutputStream(bo).writeObject(obj)
  bo.toByteArray
}

def read(bytes:Array[Byte]): Any = {
  new ObjectInputStream(new ByteArrayInputStream(bytes)).readObject()
}


read(write( {a:Int => a+1} )).asInstanceOf[ Function[Int,Int] ](5) // == 6

// And case class serialization
case class XF(f:(Int => Int)) extends Serializable

read(write(XF( {a:Int => a+1} ))).asInstanceOf[XF].f(5) // == 6 

NB. Не работает для классов, определенных во внешних классах или областях функций. (что имеет смысл, поскольку вы, вероятно, не хотели сериализовать ссылку на внешний класс).

Очень круто, но учтите, что JVM требует, чтобы загруженные ссылки на классы были доступны в пути к классам при загрузке объекта. (Это не универсальный путь сериализации, так как читателю также необходим доступ к десериализованным файлам классов компиляции)

8 голосов
/ 19 марта 2012

Нет, функция не обязательна для сериализации ... и сериализуемые функции вряд ли обеспечат удобочитаемую сериализацию.

Если вы хотите иметь возможность выполнять какие-либо функции, я боюсь, что не будет никакого решения. Возможный обходной путь, если его можно использовать в вашем сценарии, - это создать класс case, который реализует Function[Int, Boolean], и, таким образом, вернуться к сценарию класса case.

Например, предположим, что вы изолировали, что все ваши функции проверяют, является ли целое число делимым точно на данное целое число:

case class Mod(mod: Int) extends Function[Int, Boolean] { //the extends part is not even require
  def apply(x: Int) = x % mod == 0
}

case class Foo(bar: Mod, baz: Int)

Это явно ультра-ограничительный. Но я боюсь, что это лучшее, что ты можешь достичь.

Согласно вашему редактированию. Решением может быть фабричный класс:

case class IntTest(humanReadableDescription: String) {
  def apply(x: Int) = IntTest.fromString(humanReadableDescription)(x)
}

object IntTest {
  private val fromString = Map[String, Function[Int, Boolean]] (
     "mod2" -> {x:Int => x % 2 == 0},
     "is42" -> {x:Int => x == 42}
  )
}

case class Foo(bar: IntTest, baz: Int)

Но здесь вы потеряете безопасность типов.

3 голосов
/ 19 марта 2012

Семантически говоря, как бы вы сериализовали функцию ?Единственно возможный способ - это закодировать фактическую реализацию (т.е. байт-код), что возможно в обоих форматах, но само по себе является болезненным (загрузка классов, управление версиями, производительность ...)

Короче говоря, бездополнительный контекст ваш вопрос имеет очень мало смысла.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...