假设我在Scala中定义了一个函数变量:
var _f = (input:Any) => {0}
println(_f('a'));
println(_f('b'));
这很好用,给我两个零。我继续更新_f如下:
_f= (input: Any) => { if (input!='c') _f(input) else 5 }
println(_f('a'));
我希望再次获得零(请参阅问题末尾的问题更新部分),但我没有!相反,我遇到以下错误:
Exception in thread "main" java.lang.StackOverflowError
at java.lang.Character.charValue(Character.java:4398)
at scala.runtime.BoxesRunTime.equalsCharObject(BoxesRunTime.java:177)
at scala.runtime.BoxesRunTime.equals2(BoxesRunTime.java:135)
at scala.runtime.BoxesRunTime.equals(BoxesRunTime.java:125) ....
请注意,如果在上述情况下拨打println(_f('c'))
代替println(_f('a'))
秒呼叫,我会得到5。
我的问题:
1)为什么会这样?这已得到解答(请参阅更新部分)
2)如何实现上述预期行为(即更新函数变量以返回某些输入的特殊值,而不触及其他输入的行为)?
更新:
@plinth回答揭示了在上面,通过写_f(input)
我递归调用导致无限调用的_f
。但事实上,通过_f(input)
我错误地想要实现_f
函数的先前行为(而不是它的递归调用)。所以问题变为:如何在函数变量更新中访问函数的先前行为?
答案 0 :(得分:4)
在您的代码中:
_f= (input: Any) => { if (input!='c') _f(input) else 5 }
如果输入不是' c',则使用相同的输入再次调用_f。这是一个无限的非尾递归调用,因此你的堆栈将完全爆炸。
如果你的目标是在现有函数上创建一个适配器,也许你想要这样的东西:
def wrapper(f: Any => Int)(input:Any) : Int =
{
if (input != 'c') f(input)
else 5
}
然后你可以这样做:
var _f = (input:Any) => { 0 }
_f = wrapper(_f)
val x = _f('a') // x = 0
val y = _f('c') // y = 5
这样做是通过使用包装器的部分应用程序返回基于旧函数的新函数,该函数将旧函数绑定到使用它的新函数。