在SubType上对akka流进行分区

时间:2019-01-11 22:15:34

标签: scala akka akka-stream

我有一个akka流,其中有一个ADT格式。

sealed trait Message
sealed trait ThisMessage extends Message
sealed trait ThatMessage extends Message

现在,我有一个消息处理程序流和一个消息处理程序流。我有一个接受Message类型的入口流。

为了创建一个拆分,我有以下分区程序。我对分区程序功能具有以下定义。

 /**
  * Creates a Partition stage that, given a type A, makes a decision to whether to partition to subtype B or subtype C
  *
  * @tparam A type of input
  * @tparam B type of output on the first outlet.
  * @tparam C type of output on the second outlet.
  *
  * @return A partition stage
  */
  def binaryPartitionByType[A, B <: A, C <: A](): Graph[FanOutShape2[A, B, C], NotUsed] =
GraphDSL.create[FanOutShape2[A, B, C]]() { implicit builder =>
  import GraphDSL.Implicits._

  // This is wrong, but I have no idea how to write this.
  val partitioner: UniformFanOutShape[A, A] = builder.add(Partition[A](2, {
    case _: B => 0
    case _: C => 1
  }))

  new FanOutShape2(partitioner.in, partitioner.out(0).outlet, partitioner.out(1).outlet)
}

我希望使用上述方法,并在类型params中使用ADT来初始化分区程序。

编译器抛出此错误。

Error:(63, 7) type mismatch;
 found   : akka.stream.FanOutShape2[A,A,A]
 required: akka.stream.FanOutShape2[A,B,C]
      new FanOutShape2(partitioner.in, partitioner.out(0).outlet, 
partitioner.out(1).outlet)

据我了解,分区对象仅具有Inlet(在这种情况下,A为参数化类型。

任何人都知道如何解决此问题?

2 个答案:

答案 0 :(得分:1)

这是从FanOutShape2[A, B<:A, C<:A]生成的UniformFanOutShape[A, A]实例化builder.add(Partition[A]())的一种方法:

import akka.stream.scaladsl._
import akka.stream.{Graph, FanOutShape2}
import akka.NotUsed
import scala.reflect.ClassTag

def binaryPartitionByType[A, B <: A : ClassTag, C <: A : ClassTag](): Graph[FanOutShape2[A, B, C], NotUsed] =
  GraphDSL.create[FanOutShape2[A, B, C]]() { implicit builder =>
    import GraphDSL.Implicits._

    val partitioner = builder.add(Partition[A](2, {
      case _: B => 0
      case _: C => 1
    }))

    val partitionB = builder.add(Flow[A].collect{ case b: B => b })
    val partitionC = builder.add(Flow[A].collect{ case c: C => c })

    partitioner.out(0) ~> partitionB
    partitioner.out(1) ~> partitionC

    new FanOutShape2(partitioner.in, partitionB.out, partitionC.out)
}

// binaryPartitionByType: [A, B <: A, C <: A]()(
//   implicit evidence$1: scala.reflect.ClassTag[B], implicit evidence$2: scala.reflect.ClassTag[C]
// ) akka.stream.Graph[akka.stream.FanOutShape2[A,B,C],akka.NotUsed]

请注意,ClassTag可以避免类型擦除。

答案 1 :(得分:0)

问题是您试图颠覆类型系统。 UniformFanOutShape被命名为“统一”,因为其所有输出均为同一类型。如果不是那样,那么您就不需要首先创建其他FanOutShape2。如果要破坏类型系统,则应一致进行,以便更改Outlet的类型。尝试这样的事情:

new FanOutShape2(partitioner.in, partitioner.out(0).outlet.as[B], partitioner.out(1).outlet.as[C])