我一直在学习scala,我得说它是一种非常酷的语言。我特别喜欢它的模式匹配功能和函数文字,但我来自javascript,ruby背景,这些语言中我最喜欢的模式之一是惰性函数和方法定义模式。 javascript中的一个例子是
var foo = function() {
var t = new Date();
foo = function() {
return t;
};
return foo();
};
带有小调整的相同代码在ruby中工作,您只需使用单例对象在执行计算后重新定义该方法。当涉及昂贵的计算时,这种事情非常方便,如果您需要结果,则提前不知道。我知道在scala中我可以使用缓存来模拟相同类型的结果,但我正在尝试避免条件检查,到目前为止,我的实验已经返回了负面结果。有没有人知道scala中是否存在惰性函数或方法定义模式?
注意:javascript代码来自Peter Michaux的site。
答案 0 :(得分:30)
JavaScript中所有复杂的代码似乎只是尝试缓存日期的值。在Scala中,您可以轻松实现同样的目标:
lazy val foo = new Date
并且,如果甚至不想制作val,但想要调用只在需要时执行昂贵代码的函数,你可以
def maybeExpensive(doIt: Boolean, expensive: => String) {
if (doIt) println(expensive)
}
maybeExpensive(false, (0 to 1000000).toString) // (0 to 1000000).toString is never called!
maybeExpensive(true, (0 to 10).toString) // It is called and used this time
其中模式expensive: => String
被称为名称参数,您可以将其视为“给我一些将根据请求生成字符串的内容”。请注意,如果您使用它两次,它将每次重新生成,这是Randall Schultz的便利模式所在:
def maybeExpensiveTwice(doIt: Boolean, expensive: => String) {
lazy val e = expensive
if (doIt) {
println(e)
println("Wow, that was " + e.length + " characters long!")
}
}
现在只有在你需要它时才会生成(通过by-name参数)和存储它并在需要时重新使用它(通过懒惰的val)。
所以这样做,不是JavaScript的方式,即使你可以使Scala看起来很像JavaScript。
答案 1 :(得分:19)
Scala有lazy val
s,除非使用val,否则不会对其初始值设定项进行求值。延迟val可以用作方法局部变量。
Scala还有通过名称方法参数,其实际参数表达式包含在thunk中,并且每次在方法体中引用形式参数时都会计算thunk。
这些可以用来实现惰性评估语义,例如Haskell中的默认语义(至少在我对Haskell的非常有限的理解中)。
def meth(i: => Int): Something = {
// ^^^^^^ by-name parameter syntax
lazy val ii = i
// Rest of method uses ii, not i
}
在此方法中,用作实际参数的表达式将被评估为零次(如果方法体的动态执行路径从不使用ii
)或一次(如果它使用ii
一个或更多次)。
答案 2 :(得分:10)
您可以定义一个lazy val,它是一个函数:
lazy val foo = {
val d = new Date
() => { d }
}
println(foo())
foo()
现在每次都会返回相同的Date对象,这个对象将在第一次调用foo时被初始化。
为了解释一下代码,第一次调用foo(){ val d = new Date; () => { d } }
时,d被赋值给一个新的日期值,然后它计算最后一个表达式() => { d }
并将其分配给foo值。然后foo是一个没有参数返回d的函数。
答案 3 :(得分:6)
我认为一些响应者对你提出这个问题的方式感到有些困惑。您想要的Scala构造是一个简单的惰性定义:
lazy val foo = new java.util.Date
Date对象的构造最多只发生一次,并推迟到第一次引用foo。
答案 4 :(得分:3)
我对Ruby一无所知,但scala也有单例对象模式:
Welcome to Scala version 2.8.0.r22634-b20100728020027 (Java HotSpot(TM) Client VM, Java 1.6.0_20).
Type in expressions to have them evaluated.
Type :help for more information.
scala> object LazyInit {
| val msec = { println("Hi,I'm here!"); System.currentTimeMillis }
| }
defined module LazyInit
scala> System.currentTimeMillis
res0: Long = 1282728315918
scala> println(System.currentTimeMillis +" : " + LazyInit.msec)
Hi,I'm here!
1282728319929 : 1282728319930
scala> println(System.currentTimeMillis +" : " + LazyInit.msec)
1282728322936 : 1282728319930
scala> println(System.currentTimeMillis +" : " + LazyInit.msec)
1282728324490 : 1282728319930
scala>
如果要获取函数,可以将其设为函数类型的子类型:
scala> object LazyFun extends (() => Long) {
| val msec = System.currentTimeMillis
| def apply() = msec
| }
defined module LazyFun
scala> System.currentTimeMillis
res2: Long = 1282729169918
scala> println(System.currentTimeMillis + " : " + LazyFun())
1282729190384 : 1282729190384
scala> println(System.currentTimeMillis + " : " + LazyFun())
1282729192972 : 1282729190384
scala> println(System.currentTimeMillis + " : " + LazyFun())
1282729195346 : 1282729190384
答案 5 :(得分:2)
我认为你的意思是“懒函数”是函数文字或匿名函数。
在Scala中你可以做这样的事情,非常类似于你发布的javascript代码。
val foo = () => {
val t = new Date()
val foo = () => {t}
foo()
}
println ("Hello World:" + foo())
主要区别在于: