我使用graph dsl根据我看到的一些示例代码创建了一些流处理作业。一切都运行得很好,我只是很难理解符号:(更新为2.4)
def elements: Source[Foos] = ...
def logEveryNSink = // a sink that logs
def cleaner: Flow[Foos, Bars, Unit] = ...
def boolChecker(bar: Bar)(implicit ex: ExecutionContext): Future[Boolean] = ...
val mySink = Sink.foreach[Boolean](println(_))
val lastly = Flow[Bars].mapAsync(2)(x => boolChecker(x).toMat(mySink)(Keep.right)
val materialized = RunnableGraph.fromGraph(
GraphDSL.create(lastly) { implicit builder =>
baz => {
import GraphDSL.Implicits._
val broadcast1 = builder.add(Broadcast[Foos](2))
val broadcast2 = builder.add(Broadcast[Bars](2))
elements ~> broadcast1 ~> logEveryNSink(1)
broadcast1 ~> cleaner ~> broadcast2 ~> baz
~> broadcast2 ~> logEveryNSink(1)
ClosedShape
}
}
).run()
我理解包含的隐式构建器,但我不确定baz
在{ implicit builder => baz => { ...
中的含义。它只是整个形状的隐含名称吗?
答案 0 :(得分:5)
GraphDSL.create
方法严重超载,可以采用多种输入形状(包括0)。如果你没有传入初始形状,那么buildBlock
函数arg(你实际定义图形的构建方式的主体)的签名如下:
(Builder[NotUsed]) => S
所以这只是一个Function1[Builder[NotUsed], S]
,即一个函数,它接受一个Builder[NotUsed]
的实例并返回一个Shape
实例,这是最终的图形。这里的NotUsed
与Unit
是同义词,因为您没有传入任何您不关心正在生成的输出图的具体化值的输入共享。
如果您决定传入输入形状,那么buildBlock
函数的签名会稍微改变以使输入形状变得平滑。在您的情况下,您传入的是1个输入形状,因此buildBlock
的签名更改为:
(Builder[Mat]) => Graph.Shape => S
现在,这本质上是一个Function1[Builder[Mat], Function1[Graph.Shape, S]]
,或者是一个带Builder[Mat]
的函数(其中Mat
是输入形状的具体化值类型)并返回一个函数Graph.Shape
并返回S
的实例(Shape
)。
长话短说,如果你传入形状,那么你还需要在图形构建块函数中将它们声明为绑定参数,但作为第二个输入函数(因此附加=>
)。