【问题标题】:Case class .copy() and large objects案例类 .copy() 和大对象
【发布时间】:2017-08-05 01:46:54
【问题描述】:

让我们假设通过 REST 端点接收大型对象(在我的例子中是多兆字节的附件,每天数千个)并存储在这样的案例类中:

case class Box(largeBase64Object: String, results: List[String])

现在,这个案例类的实例在多个连续的步骤(链)中进行处理。每个链步骤都可以通过调用box.copy(results = "foo" :: box.results)来改变实例(其实这个例子是简化的,它实际上是一个无形的HList,它存储了每个步骤的结果)。

单个步骤可能是,例如病毒扫描,这会将扫描程序的结果(感染/未感染作为Boolean)添加到results 列表中。

但是,这种方法总是会为可能较大的附件创建一个新副本。是的,垃圾收集迟早会收集过时的副本,但我仍然担心潜在的开销,因为我们谈论的是每天几 GB 的附件数据。

另一种明显的方法是将附件存储在全局可变Map 中,并将引用存储在Box 中。这将避免每一步复制一次附件,但完全不可变数据结构的良好属性将消失。

处理这些情况的规范方法是什么?有没有人指出反映这种情况的基准(复制与全局存储)?

【问题讨论】:

  • 它不会创建附件的副本。所有副本都将引用相同的largeBase64Object 值。
  • 哦,真的吗?这很酷......你能请。将此添加为答案,以便我可以接受它
  • 杰普,复制!
  • 我实际上并不认为“结构共享”是一个相关的概念。它只是浅拷贝而不是深拷贝。

标签: scala


【解决方案1】:

案例类引用的对象不会被复制,只有案例类本身,所有引用都将指向与原始对象相同的对象(当然,您明确更改的对象除外)。

我们无法查看复制方法的源代码,因为它是由编译器生成的,但是我们可以使用-Xprint:typer 编译器标志来查看它生成的代码。

为你案例课

case class Box(largeBase64Object: String, results: List[String])

我们看到生成的方法(我使用的是scalac 2.12.3)

<synthetic> def copy(largeBase64Object: String = largeBase64Object, results: List[String] = results): Box = new Box(largeBase64Object, results);
<synthetic> def copy$default$1: String = Box.this.largeBase64Obj
<synthetic> def copy$default$2: List[String] = Box.this.results;

正如我们所见,copy 方法只是使用它传递的对象创建案例类的新实例,并且默认情况下直接使用案例类的字段而不进行任何复制。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-11-11
    • 1970-01-01
    • 2018-12-05
    • 1970-01-01
    • 2012-05-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多