考虑以下假设的二叉树遍历代码:
def visitAll(node: Node, visited: Set[Node]): Unit = {
val newVisited = visited + node
if (visited contains node) throw new RuntimeException("Cyclic tree definition")
else if (node.hasLeft) visitAll(node.left, newVisited)
else if (node.hasRight) visitAll(node.right, newVisited)
else ()
}
我想通过隐含visited
参数来减少重复,如下所示:
def visitAll(node: Node)(implicit visited: Set[Node]): Unit = {
implicit val newVisited = visited + node
if (visited contains node) throw new RuntimeException("Cyclic tree definition")
else if (node.hasLeft) visitAll(node.left) // newVisited passed implicitly
else if (node.hasRight) visitAll(node.right) // newVisited passed implicitly
else ()
}
但是,这会产生以下编译错误:
含糊不清的隐含值:类型
visited
的值Set[Node]
和newVisited
类型的值scala.collection.immutable.Set[Node]
都匹配预期类型Set[Node]
有没有办法告诉编译器只是"期待" visited
参数的隐式值,但在递归调用方法时不要将其用作隐式值?
答案 0 :(得分:0)
不幸的是,没有基于注释的解决方案,比如(@noPropagate implicit visited: Set[Node])
,所以你必须隐藏它:
scala> def visitAll(node: Node)(implicit visited: Set[Node]): Unit = {
| implicit val visited = Set[Node]()
| visitAll(node)
| }
visitAll: (node: Node)(implicit visited: Set[Node])Unit
但是,如果要访问阴影值,它将不起作用:
scala> def visitAll(node: Node)(implicit visited: Set[Node]): Unit = {
| val unshadowed: Set[Node] = visited
| implicit val visited: Set[Node] = unshadowed
| visitAll(node)
| }
<console>:10: error: forward reference extends over definition of value unshadow
ed
val unshadowed: Set[Node] = visited
^
所以,这可能会有所帮助(用REPL检查),然后:
def visitAll(node: Node)(implicit visited: Set[Node]): Unit = {
val newVisited = visited + node
;{
implicit val visited = newVisited
if (visited contains node) throw new RuntimeException("Cyclic tree definition")
else if (node.hasLeft) visitAll(node.left) // newVisited passed implicitly
else if (node.hasRight) visitAll(node.right) // newVisited passed implicitly
else ()
}
}
或者这个:
def visitAll(node: Node)(implicit visited: Set[Node]): Unit = {
({implicit visited: Set[Node] =>
if (visited contains node) throw new RuntimeException("Cyclic tree definition")
else if (node.hasLeft) visitAll(node.left) // newVisited passed implicitly
else if (node.hasRight) visitAll(node.right) // newVisited passed implicitly
else ()
})(visited + node)
}
这个想法是将你的阴影隐含在一些嵌套的代码块
中答案 1 :(得分:-1)
隐藏传入的隐含。
句法解决方案是阴影。隐含规则是当两个候选人在范围内时使用重载分辨率。候选人必须可以通过简单的名称访问。
scala> def f(implicit s: String): String = {
| val s0 = s
| if (s.length > 10) s else {
| implicit val s: String = s0 + "more"
| f
| }
| }
f: (implicit s: String)String
scala> f("hi")
res0: String = himoremoremore
如果可以利用重载解析,则可以避免阴影和重命名。这里,类型P2
表示“为递归调用做好准备。”
scala> trait P ; trait P2 extends P
defined trait P
defined trait P2
scala> def f(implicit p: P): String = {
| if (p.toString.length > 10) p.toString else {
| implicit val p2: P2 = new P2 { override def toString = p.toString + "more" }
| f
| }}
f: (implicit p: P)String
scala> f(new P2 { override def toString = "hi" })
res1: String = himoremoremore
我今天病得很重,无法做有用的工作......