Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 如何在Akka演员身上使用堆叠特征模式?_Scala_Akka_Traits - Fatal编程技术网

Scala 如何在Akka演员身上使用堆叠特征模式?

Scala 如何在Akka演员身上使用堆叠特征模式?,scala,akka,traits,Scala,Akka,Traits,我正在尝试实现一个Pub/Sub特征,使用一个可堆叠的特征与其他akka演员混合 以下是我的想法: trait PubSubActor extends Actor { abstract override def receive = super.receive orElse { case Subscribe(topic) => /* ... */ case Publish(topic, msg) => /* ... */ } } clas

我正在尝试实现一个Pub/Sub特征,使用一个可堆叠的特征与其他akka演员混合

以下是我的想法:

trait PubSubActor extends Actor {
  abstract override def receive = 
    super.receive orElse {
      case Subscribe(topic) => /* ... */
      case Publish(topic, msg) => /* ... */
    }
}

class MyActor extends Actor with PubSubActor {
  override def receive = {
    case SomeMessage(a, b, c) => /* ... */
  }
}
此时,编译器将抛出一个错误: 错误:正在重写trait MyActor中的接收方法。。。方法receive需要“抽象重写”修饰符

你能解释一下为什么这不起作用吗?我如何修复它使其工作

谢谢

更新

以下工作:

trait PubSubActor extends Actor {
  abstract override def receive = 
    super.receive orElse {
      case Subscribe(topic) => /* ... */
      case Publish(topic, msg) => /* ... */
    }
}

class MyActor extends Actor {
  override def receive = {
    case SomeMessage(a, b, c) => /* ... */
  }
}

class MyActorImpl extends MyActor with PubSubActor

但是为什么呢?为什么我可以通过这种方式得到我想要的行为,而不是另一种?有什么原因吗?我似乎无法找出这两个样本之间的根本区别,这是造成差异的原因。

试着换一种方式:

object Subscription {
  case object Subscribe
  case object Unsubscribe
}

trait Subscription {
  this: Actor =>

  import Subscription._

  var subscribers = Set.empty[ActorRef]

  def receive: Receive = {
    case Subscribe => subscribers += sender
    case Unsubscribe => subscribers -= sender
  }
}

class MyActor extends Actor with Subscription {
  def receive = super.receive orElse {
     case msg => // handle msg
  }
}
请注意,这仍然使用了可堆叠的特征模式,由于我省略了核心,这一模式被隐藏了。所以这样的方法仍然有效(至少我想我会的,我没有时间检查它是否编译)


顺便说一句,您可以阅读更多关于该模式的信息(与演员无关)。

使用Akka的可组合演员功能,您当然可以实现您想要的目标。这在本文中有一点描述

首先,基础架构代码(直接来自文档):

然后,您希望能够将行为组合成参与者:

trait PubSubActor { self:ComposableActor =>
  receiveBuilder += {
    case Subscribe(topic) => /* ... */
    case Publish(topic, msg) => /* ... */
  }
}

trait MyActor  { self:ComposableActor =>
  receiveBuilder += {
    case SomeMessage(a, b, c) => /* ... */
  }
}
最后,一个使用这些可组合行为的实际参与者:

class MyActorImpl extends ComposableActor with PubSubActor with MyActor

有一个简单而简洁的解决方案:

使用
orElse
定义链接多个接收函数的接收特征:

trait Receiving { 
  var receivers: Receive = Actor.emptyBehavior 
  def receiver(next: Actor.Receive) { receivers = receivers orElse next }
  def receive = receivers // Actor.receive definition
}
在actors中使用此选项很容易:

trait PubSubActor extends Receiving {
  receiver {
    case Publish => /* I'm the first to handle messages */
  }
}

class MyActor extends PubSubActor with Receiving {
  receiver {
    case SomeMessage => /* PubSubActor didn't handle, I receive the message */ 
  }
}

将调用第一个PubSubActor的receive。如果消息未被处理,它将被传递到MyActor的接收端。

首先,请原谅我的英语 我认为要点是抽象覆盖修饰符需要receive方法的具体实现,但在第一个构造中

class MyActor extends Actor with PubSubActor {
  override def receive = {
    case SomeMessage(a, b, c) => /* ... */
 }}
class MyActor extends Actor {
  override def receive = {
    case SomeMessage(a, b, c) => /* ... */
  }}

class MyActorImpl extends MyActor with PubSubActor
它还没有完成

原因是scala编译器对继承进行了线性化 因此,在receive的方法链中,我们有以下顺序:

 1)  override def receive = {
        case SomeMessage(a, b, c) => /* ... */
      }
 2) abstract override def receive = super.receive orElse {
        case Subscribe(topic) => /* ... */
        case Publish(topic, msg) => /* ... */
      }

 3) then Actor.receive - it hasn't an implementation
因此无法调用PubSubActor.receive,因为它使用super.receive, 反过来,super.receive依赖于Actor.receive,但Actor.receive没有实现

在第二次施工中

class MyActor extends Actor with PubSubActor {
  override def receive = {
    case SomeMessage(a, b, c) => /* ... */
 }}
class MyActor extends Actor {
  override def receive = {
    case SomeMessage(a, b, c) => /* ... */
  }}

class MyActorImpl extends MyActor with PubSubActor
我们有接收的方法链

(一)

(二)

3) 然后是Actor.receive-它没有实现

因此PubSubActor.receive可以成功调用super.receive

其他信息:


这是个好主意!我在医生身上也看到了。谢谢你提醒我!然而,这有点过分了。我宁愿有一些我可以在没有编剧的情况下与任何演员混合的东西。有什么办法吗?@user510159,我不这么认为,除非你想把一堆特性和
Receive
def混合在一起,然后把它们明确地编织在一起,比如:
def Receive=traitAReceive或lse traitbreeive或lse traitreceive
。如果你想实现这种自动复合接收构建,那么你应该坚持使用
composebleactor
的方法。从2018年起,恰当的例子是我在def receiver(next:Actor.receive){receivers=receivers或lse next}上遇到一个类型错误。我是新来的。你能告诉我该怎么做吗?当我使用这个方法时,我无法访问
receiver{…}
块中的
sender()
,我在指控
sender()
fyis使用这个方法可以使用been/unbecome吗?@naivedeveloper我不这么认为。当你使用“成为”时,你覆盖了你的接收,因此你失去了最初的“链接”定义。为什么没有一个答案被接受?
abstract override def receive = super.receive orElse {
   case Subscribe(topic) => /* ... */
   case Publish(topic, msg) => /* ... */
}
override def receive = {
   case SomeMessage(a, b, c) => /* ... */
}