【问题标题】:Problems with multiple trait mixins and Actors多个 trait mixin 和 Actor 的问题
【发布时间】:2012-04-22 22:09:09
【问题描述】:
trait A extends Actor {
  private val s = Set[Int]()

  override def act() {
    loop {
      react {
        // case code that modifies s
      }
    }
  }
}

trait B extends Actor {
  private val t = Set[String]()

  override def act() {
    loop {
      react {
        // case code that modifies t
      }
    }
  }
}

val c = new C with A with B //...?

我真正想要的是某种 B.act() and C.act() 的自动组合,但使用 trait mix-ins,只会调用 B.act()。有没有简单的方法可以做到这一点?

编辑:这是我找到的half-solution。我说“一半”是因为原始特征不再扩展Actor,并且需要将C with A with B 定义为一个类,而不是动态混入。也许我应该称之为“四分之一解决方案”?

【问题讨论】:

  • AB都可以收到消息吗?
  • 当然,为什么不呢?我想出的解决方案可以解决这个问题——如果AB 都有消息的案例处理程序,那么稍后混合的特征优先于解决。 (其实我需要把reduce改成reduceLeft。)
  • 其实,我想我可能误解了你的问题。虽然AB 可以 都为消息定义了一个案例处理程序,但只有其中一个会实际执行。但是,您确实可以控制要解决的问题。

标签: scala inheritance actor mixins traits


【解决方案1】:

也许您可以创建一个 trait 将消息转发到其他 Actor 列表,这样您就不必修改 AB

trait C extends Actor {
  private val acts: Seq[Actor] = Seq(new A{}, new B{})

  override def act() {
    acts foreach (_.start)
    loop {
      react { case x => acts foreach { _ ! x } }
    }
  }
}

您当然可以保留acts abstract 或在实例化它时用不同的集合覆盖它。

【讨论】:

  • 这是不可能的,AB 都是特质,不能被实例化。我假设您的意思是Seq(new C with A, new C with B),但请注意,这会导致C两个 副本,这可能是额外的内存开销。忽略这一点,这没关系,直到我们有 trait A extends Dtrait B extends D。现在我们有D参数的两个副本!如果AB都有修改D参数的case,我们如何同步呢?
  • @jiaweihli 确定这是可能的:见上面的代码! new A{}new Anyref with A 相同。我不同意你关于 D 的论点;演员不应该共享可变状态
  • 哦,我不知道大括号语法。 AB 不会共享可变状态,因为在所有 A 的消息处理程序和 B 的消息处理程序之间只有一个消息处理程序一次解析。 D 的所有变量应该只有 1 个副本。您提供的代码的问题是消息处理程序在特征的每个实例上解析 - 因此D 的多个副本。
【解决方案2】:

扩展 Actor 类:

import actors.Actor

class MixableActor extends Actor {
  protected var acts = List[PartialFunction[Any, Unit]]()

  final override def act() {
    loop {
      react {
        acts.reduce((a, b) => a orElse b)
      }
    }
  }

  final def receive(act: PartialFunction[Any, Unit]) {
    acts = act :: acts
  }
}

示例代码:

abstract class Node extends MixableActor {
  ...
}

trait User extends MixableActor {
  val files = scala.collection.mutable.Set[Data]()
}

trait Provider extends User {
  receive({
    case ("provide", file: Data) =>
      provide(file)
  }: PartialFunction[Any, Unit])
}

trait Consumer extends User {
  receive({
    case ("consume", file: Data) =>
      consume(file)
  }: PartialFunction[Any, Unit])
}

示例用法:

val provider = new Node with Provider
val consumer = new Node with Consumer
val provider_and_consumer = new Node with Provider with Consumer

【讨论】:

    猜你喜欢
    • 2019-08-11
    • 1970-01-01
    • 1970-01-01
    • 2015-04-15
    • 2011-02-04
    • 2011-01-20
    • 1970-01-01
    • 2021-10-01
    • 2017-01-21
    相关资源
    最近更新 更多