加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala – 自动散列的案例类

发布时间:2020-12-16 19:01:43 所属栏目:安全 来源:网络整理
导读:我正在寻找一种方法,让类的行为就像案例类,但这是自动的 hash consed. 实现整数列表的一种方法是: import scala.collection.mutable.{Map=MutableMap}sealed abstract class Listclass Cons(val head: Int,val tail: List) extends Listcase object Nil ext
我正在寻找一种方法,让类的行为就像案例类,但这是自动的 hash consed.

实现整数列表的一种方法是:

import scala.collection.mutable.{Map=>MutableMap}

sealed abstract class List
class Cons(val head: Int,val tail: List) extends List
case object Nil extends List

object Cons {
  val cache : MutableMap[(Int,List),Cons] = MutableMap.empty
  def apply(head : Int,tail : List) = cache.getOrElse((head,tail),{
    val newCons = new Cons(head,tail)
    cache((head,tail)) = newCons
    newCons
  })
  def unapply(lst : List) : Option[(Int,List)] = {
    if (lst != null && lst.isInstanceOf[Cons]) {
      val asCons = lst.asInstanceOf[Cons]
      Some((asCons.head,asCons.tail))
    } else None
  }
}

而且,比如说

scala> (5 :: 4 :: scala.Nil) eq (5 :: 4 :: scala.Nil)
resN: Boolean = false

我们得到

scala> Cons(5,Cons(4,Nil)) eq Cons(5,Nil))
resN: Boolean = true

现在我正在寻找的是一种通用的方法来实现这一点(或者是非常类似的).理想情况下,我不想要输入:

class Cons(val head : Int,val tail : List) extends List with HashConsed2[Int,List]

(或类似).有人可以拿出一些类型的系统voodoo来帮助我,还是等待宏语言可用?

解决方法

您可以为N定义几个InternableN [Arg1,Arg2,…,ResultType] traits():Internable1 [A,Z],Internable2 [A,B,Z]等等的特征定义缓存本身,我们要劫持的intern()方法和apply方法.

我们必须定义一个特征(或一个抽象类),以确保您的InternableN特征确实有一个应用方法被覆盖,让我们称之为可应用.

trait Applyable1[A,Z] {
  def apply(a: A): Z
}
trait Internable1[A,Z] extends Applyable1[A,Z] {
  private[this] val cache = WeakHashMap[(A),Z]()
  private[this] def intern(args: (A))(builder: => Z) = {
    cache.getOrElse(args,{
      val newObj = builder
      cache(args) = newObj
      newObj
    })
  }
  abstract override def apply(arg: A) = {
    println("Internable1: hijacking apply")
    intern(arg) { super.apply(arg) }
  }
}

你的类的伴侣对象必须是一个具体类实现ApplyableN与InternableN的混合.在您的随播对象中直接应用应用程序将无法正常工作.

// class with one apply arg 
abstract class SomeClassCompanion extends Applyable1[Int,SomeClass] {
  def apply(value: Int): SomeClass = {
    println("original apply")
    new SomeClass(value)
  }
}
class SomeClass(val value: Int)
object SomeClass extends SomeClassCompanion with Internable1[Int,SomeClass]

一件好事是,原始申请不需要修改以适应实习.它只创建实例,仅在需要创建时才调用.

整个事情可以(并且应该)也被定义为具有多个参数的类.对于双参数的情况:

trait Applyable2[A,Z] {
  def apply(a: A,b: B): Z
}
trait Internable2[A,Z] extends Applyable2[A,Z] {
  private[this] val cache = WeakHashMap[(A,B),Z]()
  private[this] def intern(args: (A,B))(builder: => Z) = {
    cache.getOrElse(args,{
      val newObj = builder
      cache(args) = newObj
      newObj
    })
  }
  abstract override def apply(a: A,b: B) = {
    println("Internable2: hijacking apply")
    intern((a,b)) { super.apply(a,b) }
  }
}

// class with two apply arg 
abstract class AnotherClassCompanion extends Applyable2[String,String,AnotherClass] {
  def apply(one: String,two: String): AnotherClass = {
    println("original apply")
    new AnotherClass(one,two)
  }
}
class AnotherClass(val one: String,val two: String)
object AnotherClass extends AnotherClassCompanion with Internable2[String,AnotherClass]

互动表明,Internables的apply方法在原始的apply()之前执行,只有在需要时才会被执行.

scala> import SomeClass._
import SomeClass._

scala> SomeClass(1)
Internable1: hijacking apply
original apply
res0: SomeClass = SomeClass@2e239525

scala> import AnotherClass._
import AnotherClass._

scala> AnotherClass("earthling","greetings")
Internable2: hijacking apply
original apply
res1: AnotherClass = AnotherClass@329b5c95

scala> AnotherClass("earthling","greetings")
Internable2: hijacking apply
res2: AnotherClass = AnotherClass@329b5c95

我选择使用WeakHashMap,以便在其他地方不再引用interned缓存时,不会阻止垃圾收集.

代码整齐可用as a Github gist.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读