我正在尝试表示一个不带参数的函数并且不返回任何值(如果你必须知道的话,我在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") )
给宝宝他的瓶子!
答案 0 :(得分:220)
=> Type
符号表示按名称调用,这是可以传递的many ways参数之一。如果你不熟悉它们,我建议花一些时间来阅读维基百科文章,尽管现在它主要是按值调用和按引用调用。
这意味着传递的内容是替换作为函数内部的值名称。例如,使用此功能:
def f(x: => Int) = x * x
如果我这样称呼它
var y = 0
f { y += 1; y }
然后代码将像这样执行
{ y += 1; y } * { y += 1; y }
虽然这提出了如果存在标识符名称冲突会发生什么。在传统的按名称调用中,会发生一种称为捕获避免替换的机制,以避免名称冲突。但是,在Scala中,这是以另一种方式实现的,结果相同 - 参数内的标识符名称不能引用被调用函数中的或标识符。
在解释其他两个问题之后,我还会谈到其他一些与名字相关的要点。
语法() => Type
代表Function0
的类型。也就是说,一个不带参数并返回一些东西的函数。这相当于调用方法size()
- 它不带参数并返回一个数字。
然而,有趣的是,这种语法与匿名函数文字的语法非常相似,这是造成一些混淆的原因。例如,
() => println("I'm an anonymous function")
是arity 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-arity函数存在的类型和文字之间的相似性也存在于按名称调用。换句话说,认为,因为
() => { println("Hi!") }
是() => Unit
的文字,然后是
{ println("Hi!") }
将是=> Unit
的字面值。它不是。这是一个代码块,而不是文字。
另一个混乱的来源是Unit
类型的值被写为()
,它看起来像一个0-arity参数列表(但它不是)。
答案 1 :(得分:36)
case class Scheduled(time : Int, callback : => Unit)
case
修饰符从构造函数的每个参数中生成隐式val
。因此(如有人指出)如果删除case
,则可以使用按名称调用参数。编译器可能无论如何都可能允许它,但如果它创建val callback
而不是变形为lazy val callback
,它可能会让人感到惊讶。
当您更改为callback: () => Unit
时,您的情况只需要一个函数而不是一个按名称调用的参数。显然,该函数可以存储在val callback
中,所以没有问题。
获取所需内容的最简单方法(使用call-by-name参数传递lambda的Scheduled(40, println("x") )
)可能会跳过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
答案 2 :(得分:0)
我这样做(只是不想中断申请):
case class Thing[A](..., lazy: () => A) {}
object Thing {
def of[A](..., a: => A): Thing[A] = Thing(..., () => a)
}
并调用它
Thing.of(..., your_value)