我有一个简单的构建器,它接受来自Akka流的Source
和Sink
,并且在编译时验证在这些上执行的方法是否具有匹配源和接收器的类型。
class EventProcessorTask(config: EventProcessorConfig =
EventProcessorConfig()) {
def source[In, MatIn](source: Source[In, MatIn]): SourcedTask[In, MatIn] = new SourcedTask[In, MatIn](source, config)
}
class SourcedTask[In, MatIn](source: Source[In, MatIn], config: EventProcessorConfig) {
def withPartitioning[Id](partitioningF: In => Id): SourcedTaskWithPartitioning[In, MatIn, Id] =
new SourcedTaskWithPartitioning[In, MatIn, Id](source, partitioningF, config)
}
class SourcedTaskWithPartitioning[In, MatIn, Id](source: Source[In, MatIn], partitioningF: In => Id, config: EventProcessorConfig) {
def withSink[Out, T](sink: Sink[Out, T]): WiredTask[In, MatIn, Out :: HNil, Id, Sink[Out, T] :: HNil] =
new WiredTask[In, MatIn, Out :: HNil, Id, Sink[Out, T] :: HNil](source, sink :: HNil, partitioningF, config)
}
class WiredTask[In, MatIn, L <: HList, Id, SinksTypes <: HList](
source: Source[In, MatIn],
sinks: SinksTypes,
partitioningF: In => Id,
config: EventProcessorConfig
) {
def withSink[Out, T](sink: Sink[Out, T]): WiredTask[In, MatIn, Out :: L, Id, Sink[Out, T] :: SinksTypes] =
new WiredTask[In, MatIn, Out :: L, Id, Sink[Out, T] :: SinksTypes](
source, sink :: sinks, partitioningF, config
)
def execute[N <: Nat, P <: Product, F, R <: HList, SinksRev <: HList]
( executionMethod: In => Future[P])(
implicit generic: Generic.Aux[P, R],
rev: Reverse.Aux[L, R],
sinksRev: Reverse.Aux[SinksTypes, SinksRev],
executionContext: ExecutionContext,
l: Length.Aux[SinksRev, N]
): Unit = {
val sinksReversed = sinksRev(sinks)
// val sinksLength= sinksReversed.length.toInt
}
}
上面的代码编译但是当我尝试为Broadcast
构建Sinks
时,我甚至无法获得列表的大小(注释掉代码)。下一步是将Sinks
中的所有SinksRev
与P
中的相应类型相匹配,这样我就可以发送由executionMethod
生成的消息,该消息将元组返回{{1}对应于Sinks
类型。
即。
P
new EventProcessorTask()
.source(Source.single("str"))
.withPartitioning(r => 1)
.withSink(Sink.head[Long])
.withSink(Sink.foreach((s: String) => ()))
.execute(
in => Future.successful((null.asInstanceOf[Long], null.asInstanceOf[String]))
)
应该转到第一个Long
,Sink
转到第二个。
非常感谢任何帮助。我可能在这里做了一些非常错误的事情,但是当我开始研究这个概念时,这个概念似乎很好(现在不是那么多)。无论哪种方式,我想了解我在这里缺少的东西。
总结一下,问题是:
1.为什么我不能String
表示Int
大小?
2.如何将SinksRev
中的Sink
与SinksRev
中的相应元素相匹配,以构建基于P
的{{1}}?
答案 0 :(得分:1)
我最近自己变成了无形的和akka流,所以我决定尝试这个问题。你的情况看起来很复杂,所以我采用了我理解的东西,简化了一下代码似乎做了类似于你可能想要的东西。我仍然无法计算长度,但由于它是一个建造者,那么+= 1
就足够了。
这是使用选项而不是接收器的结果。它需要选项列表并将功能应用于选项的内容。正如我所提到的,我简化了案例。
import shapeless._
object Shapes extends App {
import ops.function._
import syntax.std.function._
case class Thing[Types <: HList, Out] private(sources: List[Option[_]]) {
def withOption[T](o: Option[T]) = Thing[T :: Types, Out](o :: sources)
def withOutput[T] = Thing[Types, T](sources)
def apply[F](f: F)(implicit fp: FnToProduct.Aux[F, Types => Out]) = {
val a: Types = sources.foldLeft[HList](HNil)((m, v) ⇒ v.get :: m ).asInstanceOf[Types]
f.toProduct(a)
}
}
object Thing {
def withOption[T](o: Option[T]) = Thing[T :: HNil, AnyVal](o :: Nil)
}
val r = Thing
.withOption(Some(1))
.withOption(Some(2))
.withOption(Some(3))
.withOutput[Unit]
.apply {
(x: Int, y: Int, z: Int) ⇒ println(x + y + z)
}
println(r)
}