可序列化和 AnyVal

发布于 2024-11-07 05:47:31 字数 660 浏览 0 评论 0原文

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

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

问题在于,如果参数不是可序列化的或 Java 的基本类型之一,则该方法会抛出 NotSerialized 异常。

我想出了以下解决方案来在编译时捕获此错误……

type Func = (A => B) with Serializable

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

但现在不可能再传递 AnyVal 类型的参数,例如 IntFloatDouble 未显式实现可序列化

方法签名应该如何设计,以使其仅接受可序列化对象或 AnyVal 类型的对象作为参数?

I am search for the right signature of a method that takes a function func and an argument arg, copies them over the network to a remote computer and returns the result. Currently the signature looks like this:

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

The problem with this is that the method throws a NotSerializable Exception if the arguments are not Serializable or one of Java's primitive types.

I came up with the following solution to catch this error at compile time ...

type Func = (A => B) with Serializable

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

... but now it is not possible anymore to pass arguments of type AnyVal like Int, Float or Double which do not explicitly implement Serializable.

How should the method signature look like such that it accepts only Serializable objects or objects of type AnyVal as argument?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

温柔一刀 2024-11-14 05:47:31

您可以使用带有自定义特征的隐式 上下文绑定 并提供隐式AnyValSerialized 到该特征的转换。

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.Serialized 提供了一些隐式参数,因此它将编译在那种情况下。

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

然后,你的签名就变成:

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

You can use a context bound implicit with a custom trait and provide implicit conversions for AnyVal and Serializable to that trait.

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]

The compiler will look for an implicit parameter based on the type and because some are provided for T <: AnyVal and T <: java.io.Serializable it will compile in that case.

You can stick the implicit definitions in the companion object for Ser so that they are available where needed.

Then, your signature becomes:

def invokeRemote[A:Ser, B:Ser](address: String, func: A => B, arg: A): B
划一舟意中人 2024-11-14 05:47:31

使用 Serialized 作为参数类型在实践中是行不通的,因为您可能拥有实际上不可序列化的 Serialized 实例:

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 集合特征不继承 Serialized (实现继承)。

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])

可序列化是一个运行时属性,不能单独由类型强制执行。使用可序列化作为参数类型不会使您避免运行时序列化错误。您要做的就是让您的函数更难调用,就像您已经体验过 AnyVal 一样(这只是冰山一角)。

Using Serializable as argument type does not work in practice, because you can have Serializable instances that are not in fact 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)

Moreover, Scala collection traits do not inherit Serializable (the implementations do).

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])

Being Serializable is a runtime property and cannot be enforced by types alone. Using Serializable as argument type will not save you from runtime Serialization errors. All you will accomplish is make your functions harder to call, as you are already experiencing with AnyVal (and that is just the tip of the iceberg).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文