2016-12-02 3 views
0

Я стараюсь применить идею implicit в Scala to Akka Streams.Akka Streams: Почему GraphDSL.Builder должен быть помечен как неявный?

Согласно http://docs.scala-lang.org/overviews/core/implicit-classes.html, основная концепция implicit класса в Scala является то, что для 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 и Акку, моя неудовлетворителен теория до сих пор является то, что с помощью create() из GraphDSL создает RunnableGraph пропусканием Builder в него.

Почему он должен быть помечен как implicit? Если это не указано, операторы ~> больше не могут быть разрешены, даже если GraphDSL.Implicits._ явно импортирован.

ответ

2

implicit имеет несколько вариантов использования в Scala, один из которых является неявным классом, о котором вы упоминаете. Однако есть также implicit parameters и implicit conversions. Я рекомендую читать на них, это немного зависит от объема этого ответа и без необходимости дублирует информацию. Обратите внимание, однако, что неявные классы в основном syntactic sugar for a class with an implicit conversion, поэтому они работают одинаково.

Если не указано, операторы ~> не могут быть решены больше, даже если GraphDSL.Implicits._ явно импортирован.

Это импортирует неявной Конверсии к FlowOps где ~> фактически определяется. В этот момент Скала знает об этом. Однако для фактического выполнения этого требуется неявный параметрb : Builder[_]. Посмотрите на определение преобразования в Implicits:

implicit def fanOut2flow[I, O](j: UniformFanOutShape[I, O])(implicit b: Builder[_]): PortOps[O] 

Теперь вы можете пометить любую Builder[_] как неявное и Scala заполнит этот параметр для вас автоматически, если он отсутствует. Удаление ключевого слова implicit из вашего Builder означает, что для заполнения этого параметра больше не существует неявного значения, что означает, что преобразование не может произойти, а затем метод ~> недоступен.

Вы, однако, свободно вызвать неявное преобразование вручную и заполнить недостающий параметр самостоятельно (в обходе всей неявной функции параметра), но это будет выглядеть очень некрасиво/многословными по сравнению:

in ~> // .. and so on 
// would become 
fanOut2flow(in)(builder) ~> // .. and so on 
+0

Спасибо очень много для этого подробного объяснения! Я не обращал достаточного внимания, чтобы понять, что для неявного преобразования требуется, чтобы строитель был как (неявный) параметр. Спасибо что подметил это! – Toaditoad

Смежные вопросы