Serializable和AnyVal

gru*_*ewa 6 scala

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

def invokeRemote[A,B](address: String, func: A => B, arg: A): B
Run Code Online (Sandbox Code Playgroud)

这样做的问题是,如果参数不是Serializable或Java的原始类型之一,则该方法抛出NotSerializable Exception.

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

type Func = (A => B) with Serializable

def invokeRemote[A <: Serializable, B <: Serializable](address: String, func: Func, arg: A): B
Run Code Online (Sandbox Code Playgroud)

...但现在不可能再传递AnyVal类型的参数,如Int,Float或Double,它们没有显式实现Serializable.

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

huy*_*hjl 9

您可以使用隐式自定义特征的上下文绑定,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]
Run Code Online (Sandbox Code Playgroud)

编译器会基于类型的隐含参数,因为有些是提供T <: AnyVal和T <: java.io.Serializable它在这种情况下进行编译.

您可以将隐式定义粘贴在随播对象中,Ser以便在需要时可用.

然后,您的签名变为:

def invokeRemote[A:Ser, B:Ser](address: String, func: A => B, arg: A): B
Run Code Online (Sandbox Code Playgroud)