Сериализуемый и AnyVal - PullRequest
6 голосов
/ 14 мая 2011

Я ищу правильную сигнатуру метода, который принимает функцию func и аргумент arg , копирует их по сети на удаленный компьютер и возвращает результат.В настоящее время подпись выглядит следующим образом:

def invokeRemote[A,B](address: String, func: A => B, arg: A): B

Проблема заключается в том, что метод генерирует исключение NotSerializable, если аргументы не являются Serializable или одним из примитивных типов Java.

Я пришелс помощью следующего решения, чтобы перехватить эту ошибку во время компиляции ...

type Func = (A => B) with Serializable

def invokeRemote[A <: Serializable, B <: Serializable](address: String, func: Func, arg: A): B

... но теперь больше невозможно передавать аргументы типа AnyVal подобно Int, Float или Double , которые явно не реализуют Serializable .

Как должна выглядеть подпись метода, чтобы он принимал толькоСериализуемые объекты или объекты типа AnyVal в качестве аргумента?

Ответы [ 3 ]

9 голосов
/ 14 мая 2011

Вы можете использовать привязанный к контексту неявный с пользовательской чертой и предоставлять неявные преобразования для AnyVal и Serializable в эту черту.

trait Ser[M]

implicit def toSer1[T <: AnyVal]: Ser[T] = new Ser[T] {}
implicit def toSer2[T <: java.io.Serializable]: Ser[T] = new Ser[T] {}

def f[T: Ser](a:T): T = a
f(1)
// res2: Int = 1
f("123")
// res3: java.lang.String = 123
f(new Object)
// could not find implicit value for evidence parameter of type Ser[java.lang.Object]

Компилятор будет искатьнеявный параметр, основанный на типе, и поскольку некоторые из них предусмотрены для T <: AnyVal и T <: java.io.Serializable, он будет скомпилирован в этом случае.

Вы можете прикрепить неявные определения в сопутствующем объекте для Ser, чтобы они были доступны там, где это необходимо.

Затем ваша подпись становится:

def invokeRemote[A:Ser, B:Ser](address: String, func: A => B, arg: A): B
1 голос
/ 02 сентября 2012

Использование Serializable в качестве типа аргумента на практике не работает, поскольку у вас могут быть экземпляры Serializable, которые на самом деле не сериализуемы:

class NotSerializable(val s: String)

// ArrayList inherits Serializable
val list = new java.util.ArrayList[NotSerializable]()

list.add(new NotSerializable("test"))

// will fail at run time
serialize(list)

Более того, черты коллекции Scala не наследуют Serializable (реализации делают).

def f(s: Serializable) { println(s) }

// will fail to compile, because interface List does not inherit Serializable
f(List("a", "b"))

// will print true because list implementation is Serializable
println(List("a", "b").isInstanceOf[Serializable])

Быть сериализуемым является свойством времени выполнения и не может быть принудительно применено только типами.Использование Serializable в качестве типа аргумента не спасет вас от ошибок сериализации во время выполнения.Все, что вам нужно сделать, это усложнить вызов ваших функций, поскольку вы уже испытываете трудности с AnyVal (и это только верхушка айсберга).

0 голосов
/ 09 сентября 2012

Это может показаться странным и странным, но я бы посоветовал рассмотреть возможность передачи не двоичного кода Java в качестве кода, а, скажем, кода javascript (возможно, в форме coffescript) и использования Rhino на стороне выполнения.

Для этого есть серьезные причины, например, типизированные лямбды для внутренних и нетипизированные для обмена, но теории пока нет.

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