缓存 Scala Case Class 个实例

Caching Scala Case Class Instances

假设我们有以下情况classes:

abstract sealed class Tree
case class Leaf(i: Int) extends Tree
case class Node(left: Tree, right: Tree) extends Tree

每次我们调用一个caseclass构造函数,都会在内存中创建一个新对象。例如,在下面的代码中:

val a = Leaf(0)
val b = Leaf(0) 

a 和 b 指向内存中不同的对象:

a == b // true
a eq b // false

我想重写 case classes 的 "apply" 方法,使它们 return 成为缓存对象,以防它已经存在,因此,在上面的最小示例,"a eq b" 将 return 为真。

我在 Whosebug 中找到了这两个相关的答案:

我计划以结合上面链接的两种方法的方式实现我的覆盖 "apply" 方法和缓存。但我想知道我是否应该考虑其他方法。如果您知道,能否请您在这里分享您的解决方案?

缓存 case classes 的实例似乎是减少内存消耗的非常有用且自然的事情。然而,我计划实施的解决方案(基于上面链接的两个答案)似乎相​​当复杂,需要大量样板代码,这会损害 case classes 的优雅和简洁性。有谁知道 Scala 语言的未来版本是否允许我们通过编写像这样简单的东西来实现 case class 实例缓存:

abstract sealed class Tree
cached case class Leaf(i: Int) extends Tree
cached case class Node(left: Tree, right: Tree) extends Tree

??

Caching instances of case classes seems to be a very useful and natural thing to do to reduce memory consumption.

请注意,这甚至不是自动改进,很大程度上取决于案例的使用模式 class(不只是你的,而是任何使用你的库的人):

  1. 您需要考虑内存缓存需求以及无法对缓存中引用的实例进行垃圾回收(请注意,使用 WeakHashMap 无济于事:它需要 "that value objects do not strongly refer to their own keys, either directly or indirectly").

  2. 如果键是原语(如 Leaf),它们需要在查找之前装箱,这通常已经是构造函数调用。

  3. 映射中的查找比简单的构造函数调用慢得多。

  4. 逃逸分析通常会确保对象不是实际构造的,同时确保您的程序如同那样工作。当然,缓存将确保对象 do escape.

但是忽略所有这些,您可以编写一个宏注释,它将允许您 @cached case class Leaf(i: Int) extends Tree 并生成您想要的代码(或者至少 @cachedcase class;我不确定您是否会否则可以覆盖 apply)。由于上述原因,我只是不希望它很快成为该语言的一部分。