如何将do-nothing处理程序设置为by-name参数?

时间:2012-01-08 07:43:36

标签: 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一个默认的do-nothing值,我可以把代码编写为:

treeNode("aaa") {
    treeNode("bbb")
    treeNode("ccc")
}

帮助〜

2 个答案:

答案 0 :(得分:9)

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

有一个例外:根本不需要引用隐式参数块。不幸的是,你不允许使用call-by-name隐式参数,即使你是,你的签名也会允许任何随机的隐式参数在那个地方工作!

现在,有一种解决方法,我将展示完整性,但我建议(假设您不只是想要其他名称,如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,()))

(在你的例子中,你不返回任何东西;我这样做,以证明它有效。)

但是,为了避免一些{},这是很多工具,这就是为什么我建议只做这个,如果你预计这是一个非常频繁使用的DSL 这两个名字是不可接受的。 (另外,如果你期望它被大量使用,treeNode可能只是名字的痛苦;我建议只node。)

答案 1 :(得分:6)

AFAICT默认情况下,你无法传递一种空格。

顺便说一下,您可以通过创建另一个treeNode来简单地根据您的def leaf(text:String) = treeNode(t) {}功能对任务进行分区<{1}}