gpt4 book ai didi

java - 如何序列化 Scala 中的函数?

转载 作者:行者123 更新时间:2023-11-29 04:23:18 25 4
gpt4 key购买 nike

我正在学习 akka-persistence,并遇到了对象序列化的典型问题。我的对象(如下所示)具有基本类型和功能。我读了this , thisthis ,但没有人帮助我使以下序列化。

测试工具

object SerializationUtil {
def write(obj: Any): String = {
val temp = Files.createTempFile(null, null).toFile
val out = new ObjectOutputStream(new FileOutputStream(temp))
out.writeObject(obj)
out.close()

temp.deleteOnExit()
temp.getAbsolutePath
}

def read[T](file: String) = {
val in = new ObjectInputStream(new FileInputStream(new File(file)))
val obj = in.readObject().asInstanceOf[T]
in.close()
obj
}
}

统计

case class Stats(
app: String,
unit: ChronoUnit,
private var _startupDurations: List[Long]
) {
def startupDurations = _startupDurations.sorted

def startupDurations_=(durations: List[Long]) = _startupDurations = durations

@transient lazy val summary: LongSummaryStatistics = {
_startupDurations.asJava.stream()
.collect(summarizingLong(identity[Long]))
}
}

Stats 序列化得很好。

"SerializationUtil" should "(de)serialize Stats" in {
val file = SerializationUtil.write(newStats())
val state = SerializationUtil.read[Stats](file)

verifyStats(state)
}

但这不是:case class GetStatsForOneRequest(app: String, callback: Stats => Unit)

java.io.NotSerializableException: org.scalatest.Assertions$AssertionsHelper
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)

还试过:

trait SerializableRunnable[T] extends scala.Serializable with ((T) => Unit)

将回调实现为 SerializableRunnable 的实例,但没有成功。

想法?

编辑:

也许我应该澄清遇到此问题的实际用例以提供更多上下文。该函数是来自 Akka HTTP 的回调 route像下面这样:

path("stats") {
logRequest("/stats") {
completeWith(instanceOf[List[Stats]]) { callback =>
requestHandler ! GetStatsRequest(callback)
}
}
}

handler actor 坚持请求直到它得到响应。构建最终输出可能需要多个响应。

我做了一些挖掘,回调实现似乎是一个 CallbackRunnable .

最佳答案

也许您没有完全理解链接的文章。函数序列化的问题在于闭包中捕获的任何内容也必须是可序列化的。你需要的是Spores .一切都在那里解释,但这里是要点:

什么是闭包?

Scala 中的 Lambda 函数可以引用外部作用域中的变量,而无需将它们显式列为参数。执行此操作的函数称为闭包,它引用的外部变量是捕获的。例如 foo 在传递给下面的 map 的闭包中被捕获:

val foo = 42
List(1,2,3).map(_ + foo)

为什么序列化有问题?

看看上面的示例,其中 foo 是一个原始值,您不会认为这是一个问题。但是当有封闭类时会发生什么?

class C {
val myDBconn = ...
val foo = 42
List(1,2,3).map(_ + foo)
}

现在(对许多程序员来说出乎意料)闭包捕获了非序列化封闭类的整个 this,包括 myDBconn,因为 foo引用getter方法this.foo

解决方案是什么?

解决方案是不在闭包中捕获this。例如,为我们需要捕获的任何值创建一个本地 val 使函数再次可序列化:

class C {
val myDBconn = ...
val foo = 42
{
val localFoo = foo
List(1,2,3).map(_ + localFoo)
}
}

当然,手动执行此操作很乏味,因此 Spores .

关于java - 如何序列化 Scala 中的函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47806670/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com