在Scala中的函数类型变量更新中访问函数的先前行为

时间:2015-06-12 17:18:57

标签: scala

假设我在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函数的先前行为(而不是它的递归调用)。所以问题变为:如何在函数变量更新中访问函数的先前行为?

1 个答案:

答案 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

这样做是通过使用包装器的部分应用程序返回基于旧函数的新函数,该函数将旧函数绑定到使用它的新函数。