Akka Streams:为什么 GraphDSL.Builder 必须标记为隐式?
Akka Streams: Why does the GraphDSL.Builder have to be marked as implicit?
我很难将 Scala 中 implicit
的想法应用到 Akka Streams。
根据 http://docs.scala-lang.org/overviews/core/implicit-classes.html,Scala 中 implicit
class 的基本概念是为 5 times prinln("foo")
创建一个 IntWithTimes
的对象,使得方法 times
通过导入 Helpers._
.
隐式可用
object Helpers {
implicit class IntWithTimes(x: Int) {
def times[A](f: => A): Unit = {
def loop(current: Int): Unit =
if(current > 0) {
f
loop(current - 1)
}
loop(x)
}
}
}
让我们考虑以下示例:
val g = RunnableGraph.fromGraph(GraphDSL.create() {
implicit builder: GraphDSL.Builder[Unit] =>
import GraphDSL.Implicits._
val in = Source(1 to 100)
val flow = Flow[Int].map(_ + 1)
val out = Sink.foreach(println)
in ~> flow ~> out
ClosedShape
})
g.run()
显然是 Scala 和 Akka 的新手,到目前为止我不满意的理论是使用 GraphDSL
的 create()
通过将 Builder
传递给它来创建 RunnableGraph
。
为什么要标记为implicit
?如果离开,~>
运算符将无法再解析 - 即使 GraphDSL.Implicits._
已明确导入。
implicit
在 Scala 中有多个用例,其中之一是您提到的隐式 类 。但是,也有implicit parameters and implicit conversions. I recommend reading up on those, it's a bit much for the scope of this answer and would needlessly duplicate information. Note however that implicit classes are mostly ,所以它们的作用是一样的。
If left away, the ~> operators cannot be resolved anymore - even though GraphDSL.Implicits._ is explicitly imported.
这会将隐式 conversions 导入到 FlowOps
,其中实际定义了 ~>
。此时 Scala 知道转换。然而,要实际执行此操作,它需要一个隐式的 参数 b : Builder[_]
。看看Implicits
:
中的转换定义
implicit def fanOut2flow[I, O](j: UniformFanOutShape[I, O])(implicit b: Builder[_]): PortOps[O]
现在您可以将任何 Builder[_]
标记为隐式,如果缺少此参数,Scala 会自动为您填充。从您的构建器中删除 implicit
关键字意味着不再有任何隐式值可用于填充此参数,这意味着转换无法发生,随后方法 ~>
不可用。
然而,您可以自由地手动调用隐式转换并自己填写缺少的参数(绕过整个隐式参数功能),但相比之下,这看起来非常 ugly/verbose:
in ~> // .. and so on
// would become
fanOut2flow(in)(builder) ~> // .. and so on
我很难将 Scala 中 implicit
的想法应用到 Akka Streams。
根据 http://docs.scala-lang.org/overviews/core/implicit-classes.html,Scala 中 implicit
class 的基本概念是为 5 times prinln("foo")
创建一个 IntWithTimes
的对象,使得方法 times
通过导入 Helpers._
.
object Helpers {
implicit class IntWithTimes(x: Int) {
def times[A](f: => A): Unit = {
def loop(current: Int): Unit =
if(current > 0) {
f
loop(current - 1)
}
loop(x)
}
}
}
让我们考虑以下示例:
val g = RunnableGraph.fromGraph(GraphDSL.create() {
implicit builder: GraphDSL.Builder[Unit] =>
import GraphDSL.Implicits._
val in = Source(1 to 100)
val flow = Flow[Int].map(_ + 1)
val out = Sink.foreach(println)
in ~> flow ~> out
ClosedShape
})
g.run()
显然是 Scala 和 Akka 的新手,到目前为止我不满意的理论是使用 GraphDSL
的 create()
通过将 Builder
传递给它来创建 RunnableGraph
。
为什么要标记为implicit
?如果离开,~>
运算符将无法再解析 - 即使 GraphDSL.Implicits._
已明确导入。
implicit
在 Scala 中有多个用例,其中之一是您提到的隐式 类 。但是,也有implicit parameters and implicit conversions. I recommend reading up on those, it's a bit much for the scope of this answer and would needlessly duplicate information. Note however that implicit classes are mostly
If left away, the ~> operators cannot be resolved anymore - even though GraphDSL.Implicits._ is explicitly imported.
这会将隐式 conversions 导入到 FlowOps
,其中实际定义了 ~>
。此时 Scala 知道转换。然而,要实际执行此操作,它需要一个隐式的 参数 b : Builder[_]
。看看Implicits
:
implicit def fanOut2flow[I, O](j: UniformFanOutShape[I, O])(implicit b: Builder[_]): PortOps[O]
现在您可以将任何 Builder[_]
标记为隐式,如果缺少此参数,Scala 会自动为您填充。从您的构建器中删除 implicit
关键字意味着不再有任何隐式值可用于填充此参数,这意味着转换无法发生,随后方法 ~>
不可用。
然而,您可以自由地手动调用隐式转换并自己填写缺少的参数(绕过整个隐式参数功能),但相比之下,这看起来非常 ugly/verbose:
in ~> // .. and so on
// would become
fanOut2flow(in)(builder) ~> // .. and so on