我试图表示一个不带参数、不返回值的函数(如果您一定要知道,我正在用JavaScript模拟setTimeout函数)。
case class Scheduled(time : Int, callback : => Unit)
不能编译,因为“` `val‘参数可能不是按名称调用的”
case class Scheduled(time : Int, callback : () => Unit)
编译,但必须奇怪地调用,而不是
Scheduled(40, { println("x") } )
我必须这么做
Scheduled(40, { () => println("x") } )
同样有效的是
class Scheduled(time : Int, callback : Unit => Unit)
而是以一种更不明智的方式调用的
Scheduled(40, { x : Unit => println("x") } )
(类型为Unit的变量是什么?)当然,我想要的是一个构造函数,它可以像调用普通函数一样被调用:
Scheduled(40, println("x") )
把奶瓶给宝宝!
发布于 2010-12-28 19:32:37
Call-by-Name:=>类型
=> Type
表示call-by-name,这是可以传递的many ways参数之一。如果您不熟悉它们,我建议您花一些时间阅读wikipedia文章,尽管现在它主要是按值调用和按引用调用。
它的意思是传递的内容将替换函数中的值名。例如,以此函数为例:
def f(x: => Int) = x * x
如果我这样称呼它
var y = 0
f { y += 1; y }
然后,代码将像这样执行
{ y += 1; y } * { y += 1; y }
不过,这提出了如果存在标识符名称冲突时会发生什么的问题。在传统的按名称调用中,会发生一种称为捕获避免替换的机制,以避免名称冲突。然而,在Scala中,这是以另一种方式实现的,具有相同的结果--参数中的标识符名称不能引用或隐藏被调用函数中的标识符。
还有一些与call-by-name相关的其他要点,我将在解释完其他两个之后再谈到。
0参数函数:() =>类型
语法() => Type
代表Function0
的类型。也就是说,一个不带参数并返回一些东西的函数。比方说,这相当于调用方法size()
--它不接受任何参数并返回一个数字。
然而,有趣的是,这种语法与匿名函数文本的语法非常相似,这是造成一些混淆的原因。例如,
() => println("I'm an anonymous function")
是一个参数为0的匿名函数文本,其类型为
() => Unit
所以我们可以这样写:
val f: () => Unit = () => println("I'm an anonymous function")
但是,重要的是不要混淆类型和值。
单位=>类型
这实际上只是一个Function1
,它的第一个参数的类型是Unit
。其他的编写方式可以是(Unit) => Type
或Function1[Unit, Type]
。问题是..。这不太可能是人们想要的。Unit
类型的主要用途是指示一个不感兴趣的值,因此接收该值没有任何意义。
例如,考虑以下内容:
def f(x: Unit) = ...
可以用x
做什么呢?它只能有一个值,所以不需要接收它。一种可能的用途是链接返回Unit
的函数
val f = (x: Unit) => println("I'm f")
val g = (x: Unit) => println("I'm g")
val h = f andThen g
因为andThen
只在Function1
上定义,而我们链接的函数返回Unit
,所以我们必须将它们定义为Function1[Unit, Unit]
类型才能链接它们。
混乱的来源
混淆的第一个来源是,认为类型和文字之间的相似性对于0度函数来说也存在,对于按名称调用也存在。换句话说,认为,因为
() => { println("Hi!") }
是() => Unit
的文字,则
{ println("Hi!") }
将是=> Unit
的文字。事实并非如此。这是一段代码,而不是文字。
另一个造成混淆的原因是Unit
类型的值被写成()
,这看起来像一个0参数列表(但它不是)。
发布于 2010-12-28 10:49:45
case class Scheduled(time : Int, callback : => Unit)
case
修饰符对构造函数的每个参数进行隐式val
。因此(正如有人指出的那样),如果您删除了case
,则可以使用call-by-name参数。编译器可能无论如何都会允许它,但如果它创建了val callback
而不是变形为lazy val callback
,可能会让人们感到惊讶。
当您现在更改为callback: () => Unit
时,您的用例只接受一个函数,而不是一个按名称调用的参数。显然,函数可以存储在val callback
中,所以没有问题。
获得所需内容(Scheduled(40, println("x") )
,其中按名称调用参数用于传递lambda)的最简单方法可能是跳过case
,显式地创建最初无法获得的apply
:
class Scheduled(val time: Int, val callback: () => Unit) {
def doit = callback()
}
object Scheduled {
def apply(time: Int, callback: => Unit) =
new Scheduled(time, { () => callback })
}
使用中:
scala> Scheduled(1234, println("x"))
res0: Scheduled = Scheduled@5eb10190
scala> Scheduled(1234, println("x")).doit
x
发布于 2018-09-15 04:55:15
在这个问题中,您想要在JavaScript中模拟SetTimeOut函数。根据前面的答案,我编写了以下代码:
class Scheduled(time: Int, cb: => Unit) {
private def runCb = cb
}
object Scheduled {
def apply(time: Int, cb: => Unit) = {
val instance = new Scheduled(time, cb)
Thread.sleep(time*1000)
instance.runCb
}
}
在REPL中,我们可以得到如下内容:
scala> Scheduled(10, println("a")); Scheduled(1, println("b"))
a
b
我们的模拟与SetTimeOut的行为不完全相同,因为我们的模拟是阻塞函数,而SetTimeOut是非阻塞的。
https://stackoverflow.com/questions/4543228
复制相似问题