Serializable和AnyVal

时间:2011-05-14 15:15:53

标签: scala

我正在搜索带有函数 func 和参数 arg 的方法的正确签名,将它们通过网络复制到远程计算机并返回结果。目前签名如下:

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

这个问题是如果参数不是Serializable或Java的原始类型之一,该方法抛出NotSerializable异常。

我想出了以下解决方案,以便在编译时捕获此错误...

type Func = (A => B) with Serializable

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

...但现在再也无法传递 AnyVal 类型的参数,例如 Int Float Double < / strong>未明确实现 Serializable

方法签名应该如何看起来只接受Serializable对象或AnyVal类型的对象作为参数?

3 个答案:

答案 0 :(得分:8)

您可以使用隐式自定义特征的context bound,并为该特征提供AnyValSerializable的隐式转换。

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 <: AnyValT <: java.io.Serializable提供了一些隐式参数,它将在这种情况下进行编译。

您可以将隐式定义粘贴到Ser的随播对象中,以便在需要时可以使用它们。

然后,您的签名变为:

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

答案 1 :(得分:1)

使用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(这只是冰山一角)。

答案 2 :(得分:0)

这可能听起来非常奇怪,但是我建议考虑不要将java二进制文件作为代码传递,但是,例如,javascript代码(可能是其coffescript形式),并在执行端使用Rhino。

这有很深层次的原因,比如打字的lambdas用于内部和无类型的交换,但是还没有理论。