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

Scala trait mixin中方法调用的顺序

发布时间:2020-12-16 18:50:40 所属栏目:安全 来源:网络整理
导读:我的程序结构如下: abstract class IntQueue { def get(): Int def put(x: Int)}trait Doubling extends IntQueue{ abstract override def put(x: Int) { println("In Doubling's put") super.put(2*x) }}trait Incrementing extends IntQueue { abstract o
我的程序结构如下:

abstract class IntQueue {
 def get(): Int
 def put(x: Int)
}
trait Doubling extends IntQueue{
 abstract override def put(x: Int) {
   println("In Doubling's put")
   super.put(2*x)
 }
}
trait Incrementing extends IntQueue {
 abstract override def put(x: Int) {
  println("In Incrementing's put")
  super.put(x + 1)
 }
}
class BasicIntQueue extends IntQueue {
 private val buf = new ArrayBuffer[Int]
  def get() = buf.remove(0)
  def put(x: Int) {
   println("In BasicIntQueue's put")
   buf += x
 }
}

当我做:

val incrThendoublingQueue = new BasicIntQueue with Doubling with 
                                            Incrementing
incrThendoublingQueue.put(10)
println(incrThendoublingQueue.get())

输出是:

In Incrementing’s put

In Doubling’s put

In BasicIntQueue’s put

22

我在这里订购时有点困惑.我对这种情况的线性化顺序的理解是:

BasicIntQueue -> Incrementing -> Doubling -> IntQueue -> AnyRef -> Any

所以当我调用put时,不应该首先调用BasicIntQueue的版本吗?

解决方法

不.这种情况下的线性化是

{<anonymous-local>,Incrementing,Doubling,BasicIntQueue,IntQueue,AnyRef,Any}

您可以:

>只需阅读规范并说服自己必须如此
>从规范中实现一个玩具版本的算法,看看它为各种类定义输出了什么(它有点启发,但主要是为了好玩而做)

阅读规范

section 5.1.2 of the Spec
准确地告诉您如何计算线性化.您似乎忘记了在L(c_n)… L(c_1)中反转索引1 … n.

如果应用正确的公式,则会为所涉及的特征和基类获得以下线性化:

IntQueue : {IntQueue,Any}
     Doubling : {Doubling,Any}
 Incrementing : {Incrementing,Any}
BasicIntQueue : {BasicIntQueue,Any}

如果你最后结合这些线性化来计算被实例化为incrThendoublingQueue的匿名本地类的线性化:

<anonymous-local-class>,L(Incrementing) + L(Doubling) + L(BasicInt)

你获得了上面已经显示的线性化.因此,应按此顺序调用方法:

>递增
>加倍
>基本的

这与实际输出一致.

重新实现线性化算法以获得乐趣

这实际上是规范中无依赖性的片段之一,您可以从头开始轻松实现.该
可以复制替换的连接定义
规范原样,它几乎是可运行的代码(除了有趣的加箭头有点难以打字,并且我希望它作为列表上的中缀运算符):

implicit class ConcatenationWithReplacementOps[A](list: List[A]) {
  def +^->(other: List[A]): List[A] = list match {
    case Nil => other
    case h :: t => 
      if (other contains h) (t +^-> other)
      else h :: (t +^-> other)
  }
}

建模类声明C扩展C1与… Cn也是
真的很简单:

case class ClassDecl(c: String,extendsTemplate: List[ClassDecl]) {
  def linearization: List[String] = c :: (
    extendsTemplate
      .reverse
      .map(_.linearization)
      .foldLeft(List.empty[String])(_ +^-> _)
  )
}

线性化的公式在此实现为方法.注意反过来.

规范中给出的例子:

val any = ClassDecl("Any",Nil)
val anyRef = ClassDecl("AnyRef",List(any))
val absIterator = ClassDecl("AbsIterator",List(anyRef))
val richIterator = ClassDecl("RichIterator",List(absIterator))
val stringIterator = ClassDecl("StringIterator",List(absIterator))
val iter = ClassDecl("Iter",List(stringIterator,richIterator))

println(iter.linearization.mkString("{",","}"))

完全按照规范生成输出:

{Iter,RichIterator,StringIterator,AbsIterator,Any}

现在,这是您的示例的模型:

val intQueue = ClassDecl("IntQueue",List(anyRef))
val doubling = ClassDecl("Doubling",List(intQueue))
val incrementing = ClassDecl("Incrementing",List(intQueue))
val basicQueue = ClassDecl("BasicIntQueue",List(intQueue))

val incrThendoublingQueue = ClassDecl(
  "<anonymous-local>",List(basicQueue,doubling,incrementing)
)

println(incrThendoublingQueue.linearization.mkString("{","}"))

它产生了我上面已经显示的线性化顺序:

{<anonymous-local>,Any}

一切似乎都按预期工作,没有理由写入Scala-Users.

(编辑:李大同)

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

    推荐文章
      热点阅读