第2版
好吧,也许我应该在这里解析出两个欲望。
我想,当谈到setSendTimeout(0)
部分时,我会使用类似implicitly[Socket]
的东西。
new ZContext(1) {
createSocket(ZMQ.PUB).setSendTimeout(0).//RATS!
}
我还想到了一种更通用的方法,那就是(用伪代码的术语来说):
这就是如何在某个时间点包装
T
的引用而不复制它,这样,向前看,您可以从使用它的任何表达式的值中梳理出潜在状态变化后的引用状态。如果它可以被认为是从
T
到它结束的地方的map
map
map
的链,那么很容易在它上附加/应用一个值——再次仅为map
。。。
这是一个激励人心的例子。
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!
}
下面是@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
}
}
如果在传递到withCreatePort
的函数的参数中添加implicit
修饰符,则"导入"隐式转换:
trait ConnectTest extends Provider {
getTheInstance(2).withCreatePort { implicit p =>
().makeSpecial().bindTo("foo")
}
}
这可能更危险,因为您有一个从Unit
到Port
的隐式转换,尽管它是本地封装的。这是通用的,因为Connect
是通用的。
这个技巧可能太聪明了,很难让一些站在外面阅读代码的人理解。
是的,您可以创建两个包装器,一个提供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")
}
}
我不确定你带着这个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(...)
}
这就是你要找的吗?