Fre*_*ind 4 scala pass-by-name
我定义了一个treeNode创建节点的方法,它可以有子节点.简化的代码是:
def treeNode(text:String) (children: => Any) {
val b = new TreeNode(text)
children
}
Run Code Online (Sandbox Code Playgroud)
当我使用这种方法时,我必须写:
treeNode("aaa") {
treeNode("bbb") {}
treeNode("ccc") {}
}
Run Code Online (Sandbox Code Playgroud)
您可以看到他们没有子节点的叶节点,但它们必须有一个空块{}.
有没有办法给参数children: => Any一个默认的do-nothing值,我可以把代码编写为:
treeNode("aaa") {
treeNode("bbb")
treeNode("ccc")
}
Run Code Online (Sandbox Code Playgroud)
帮助〜
问题不在于你不能给它一个do-nothing(默认)值; 问题是,即使你这样做,具有多个参数块的函数必须至少具有每个块的括号或大括号.
有一个例外:根本不需要引用隐式参数块.不幸的是,你不允许使用按名称调用的隐式参数,即使你是这样,你的签名也会允许任何随机的隐式参数在那个地方工作!
现在,有一种解决方法,我将展示完整性,但我建议(假设你不只是想要另一个名字leafNode),你只需留下尾随{}.
如果执行以下操作,您可以获得所需的语法.首先,您需要一个隐式参数,但是您可以使它成为一个包装类(可以使用Function0已存在的类,但下一步可能会产生意想不到的后果):
trait AnyByName { def eval: Any }
def treeNode(text: String)(implicit children: AnyByName) = (text,children.eval)
Run Code Online (Sandbox Code Playgroud)
现在你需要两件事 - 你需要能够将一个名字Any转换成你的新特性,你需要有一个隐含的无所事事.所以我们
implicit val nameForDoingNothing = new AnyByName { def eval = () }
implicit def wrap_any_by_name(a: => Any) = new AnyByName { def eval = a }
Run Code Online (Sandbox Code Playgroud)
现在我们恢复你以后的行为:
scala> treeNode("Hi")
res1: (String, Any) = (Hi,())
scala> treeNode("Hi") { treeNode("there") }
res2: (String, Any) = (Hi,(there,()))
Run Code Online (Sandbox Code Playgroud)
(在你的例子中,你不返回任何东西;我在这里,以证明它有效.)
{}但是,为了避免某些问题,这是很多工具,这就是为什么我建议只做这个,如果你预计这是一个非常频繁使用的DSL,并且这两个名字是不可接受的.(另外,如果你期望它被大量使用,treeNode可能只是一个名字的痛苦;我建议只是node.)
AFAICT默认情况下,您将无法传递一种空块.
顺便说一句,您可以treeNode通过创建另一个来根据您的功能简单地对任务进行分区def leaf(text:String) = treeNode(t) {}
| 归档时间: |
|
| 查看次数: |
200 次 |
| 最近记录: |