是否可以在Scala中实现(没有宏)隐式zip / unzip以实现偷偷摸摸的流畅或懒惰模式?

时间:2016-04-04 00:47:46

标签: scala

EDIT2

好吧,也许我应该在这里解析两个愿望。

我记得当到达setSendTimeout(0)部分的时候,我会使用像implicitly[Socket]这样的东西。

new ZContext(1) {
   createSocket(ZMQ.PUB).setSendTimeout(0).//RATS!
}

我还想到了一种更通用的方法,那就是(用伪代码术语):

  1. 这就是你在某个时间点包装T的引用而不复制它的方法,这样你可以向前移动,在潜在的状态从任何值的变化后梳理出引用的状态表达使用它。

  2. 如果可以将其视为map map mapT到最终结果的链,那么很容易追加/应用一个值 - 再次map ......

  3. 这是一个激励人心的例子。

      override def createLogic(inheritedAttributes: Attributes): GraphStageLogic = new GraphStageLogic(shape) {
        logger.info("Initializing ZMQ context.")
        val context = new ZContext(1)
        logger.info(s"Binding PUB socket to ${endpoint}")
        val socket = {
          val s = context.createSocket(ZMQ.PUB)
          s.setSendTimeOut(0)
          s.bind(endpoint)
          s
        }
    

    在那里看socket。出于某种原因,感觉比我需要的更加丑陋,但是setters没有返回像setSendTimeOut这样的事实的结果。

    我通常会尝试按如下方式对其进行改进:

    new ZContext(1) {
       createSocket(ZMQ.PUB).setSendTimeout(0).//RATS!
    }
    

3 个答案:

答案 0 :(得分:2)

这是@Dima的答案版本。再次设置:

trait Instance {
  def createPort(): Port
}

trait Port {
  def makeSpecial(): Unit
  def bindTo(address: Any): Unit
}

trait Provider {
  def getTheInstance(i: Int): Instance
}

现在的诀窍:

implicit class InstanceOps(i: Instance) {
  def withCreatePort(fun: (Unit => Port) => Any): Port = {
    val res = i.createPort()
    fun(_ => res)
    res
  }
}

如果您将implicit修饰符添加到传递给withCreatePort的函数的参数中,那么您将导入"导入"隐式转换:

trait ConnectTest extends Provider {
  getTheInstance(2).withCreatePort { implicit p =>
    ().makeSpecial().bindTo("foo")
  }
}

这可能更危险,因为您有UnitPort的隐式转换,尽管它是本地封装的。这是通用的,因为Connect是通用的。

这个技巧可能太聪明,也很难被一些外面的人阅读你的代码所理解。

答案 1 :(得分:1)

是的,您可以创建两个包装器,一个包含withCreatePort,另一个包含返回this的端口方法的变体:

trait Instance {
  def createPort(): Port
}

trait Port {
  def makeSpecial(): Unit
  def bindTo(address: Any): Unit
}

class PortOps(p: Port) {
  def makeSpecial()       : this.type = { p.makeSpecial()  ; this }
  def bindTo(address: Any): this.type = { p.bindTo(address); this }
}

implicit class InstanceOps(i: Instance) {
  def withCreatePort[A](fun: PortOps => A): A = fun(new PortOps(i.createPort()))
}

示例:

trait Provider {
  def getTheInstance(i: Int): Instance
}

trait Plain extends Provider {
  val instance = getTheInstance(2)
  val port = instance.createPort()
  port.makeSpecial()
  port.bindTo("foo")
}

trait Rich extends Provider {
  getTheInstance(2).withCreatePort { p =>
    p.makeSpecial().bindTo("foo")
  }
}

问题是这项努力是否值得。您还可以试用import

trait Import extends Provider {
  val instance = getTheInstance(2)
  val port = instance.createPort()
  locally {
    import port._
    makeSpecial(); bindTo("foo")
  }
}

答案 2 :(得分:1)

我不确定你要使用这个Zipped的东西......但是你在问题的开头所描述的(假设该片段末尾的port是拼写错误,并且你真的想要返回instance)可以用这样的东西来完成:

object Taps {
  implicit class Tap[T](t: T) extends Anyval {
    def tap(f: T => Unit) = { f(t); t }
  }
}

然后你可以写:

import Taps._
val instance = getTheInstance(2).tap { 
   _.createPort
   .makeSpecial
   .bindTo(...)
}

这是你在找什么?