我有一个想法(模糊),以这种方式传递(或链接)一些隐式值,而不是引用阻止f
的参数:
def block(x: Int)(f: => Unit)(implicit v: Int) = {
implicit val nv = v + x
f
}
def fun(implicit v: Int) = println(v)
如果我使用了类似的东西:
implicit val ii: Int = 0
block(1) {
block(2) {
fun
}
}
会打印3
。
如果我可以说def block(x: Int)(f: implicit Int => Unit)
。
换句话说,我正在寻找一些允许我实现这个DSL的设计模式:在嵌套块中访问一些累积值但是没有明确地将它作为参数传递。可能吗? (implicit
s不是必需的,只是提示强调我不想明确地传递那个累加器)。当然,上面的代码将打印为0。
编辑:可能的用法之一:以下列方式编写http路由
prefix("path") {
prefix("subpath") {
post("action1") { (req, res) => do action }
get("action2") { (req, res) => do action }
}
}
此处post
和get
会访问(如何?)累积前缀,例如List("path", "subpath")
或"/path/subpath/"
。
答案 0 :(得分:3)
考虑使用DynamicVariable
。它非常简单易用,而且是线程安全的:
val acc: DynamicVariable[Int] = new DynamicVariable(0)
def block(x: Int)(f: => Unit) = {
acc.withValue(acc.value + x)(f)
}
def fun = println(acc.value)
答案 1 :(得分:1)
通过implicit
传递状态很脏,会导致意外且难以追踪错误。您要求做的是构建一个函数,该函数可以通过以下方式组合:嵌套调用在某些操作上累积,而其他任何东西都使用该值来执行函数?
case class StateAccum[S](init: S){
val op: S => S
def flatMap[A <: S](f: S => StateAccum[A]) ={
val StateAccum(out) = f(s)
StateAccum(op(init, out))
}
def apply(f: S => A) = f(init)
}
这可以让您完全按照自己的方式进行操作,只需稍微调整一下即可。
现在,如果你真的想要嵌套的控制结构,你的apply必须使用一个隐式值来区分返回的类型,以便它将函数应用于一个而flatMap
到{{1} }返回。它变得疯狂,但看起来如下:
StateAccum