scala - 如何将不做任何处理的处理程序设置为按名称参数?

标签 scala pass-by-name

我定义了一个方法 treeNode创建一个节点,并且可以有子节点。简化的代码是:

def treeNode(text:String) (children: => Any) {
    val b = new TreeNode(text)
    children
}

当我使用这种方法时,我必须写:
treeNode("aaa") {
    treeNode("bbb") {}
    treeNode("ccc") {}
}

您可以看到它们没有子节点的叶节点,但是它们必须有一个空块 {} .

有没有办法给参数children: => Any一个默认的什么都不做的值,我可以将代码编写为:
treeNode("aaa") {
    treeNode("bbb")
    treeNode("ccc")
}

帮助~

最佳答案

问题不在于你不能给它一个什么都不做(默认)值;问题是,即使您这样做,具有多个参数块的函数也必须至少为每个块使用括号或大括号。

有一个异常(exception):根本不需要引用隐式参数块。不幸的是,您不允许使用按名称调用的隐式参数,即使您有,您的签名也会允许任何随机隐式参数在该位置工作!

现在,有一种方法可以解决这个问题,为了完整起见,我将展示它,但我建议(假设您不只是想要另一个名称,例如 leafNode )您只需留下结尾的 {}那里。

如果您执行以下操作,您可以准确地获得所需的语法。首先,您需要一个隐式参数,但将其设为包装类(可以使用已经存在的 Function0,但下一步可能会产生意想不到的后果):

trait AnyByName { def eval: Any }
def treeNode(text: String)(implicit children: AnyByName) = (text,children.eval)

现在你需要做两件事——你需要能够转换一个名字 Any进入你的新特征,你需要有一个隐含的无所作为。所以我们
implicit val nameForDoingNothing = new AnyByName { def eval = () }
implicit def wrap_any_by_name(a: => Any) = new AnyByName { def eval = a }

现在我们恢复了您所追求的行为:
scala> treeNode("Hi")
res1: (String, Any) = (Hi,())

scala> treeNode("Hi") { treeNode("there") }
res2: (String, Any) = (Hi,(there,()))

(在您的示例中,您不返回任何内容;在这里我这样做,以表明它有效。)

很多工具只是为了避免一些 {} s,不过,这就是为什么我建议仅在您预计这是一个非常频繁使用的 DSL 并且这两个名称是 Not Acceptable 情况下才这样做的原因。 (另外,如果你希望它被大量使用, treeNode 作为一个名字可能很长;我建议只是 node 。)

关于scala - 如何将不做任何处理的处理程序设置为按名称参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8776110/

相关文章:

Scala:模式匹配 Seq[Nothing]

Scala FlatMap 和应用上下文边界产生编译错误

scala - Akka 使用同一个端口创建两个 Tcp 连接

C++ 将选项(的子集)传递给函数的优雅方式

scala - 在 DSL 中隐藏和限定隐式变量的创建

parameter-passing - "pass-by-name"是什么?它到底是如何工作的?

templates - 是否可以覆盖表单助手?

scala - Scala 中的同步 HTTP 调用