=>之间有什么区别? ,()=>,和Unit =>

时间:2010-12-28 02:14:59

标签: scala

我正在尝试表示一个不带参数的函数并且不返回任何值(如果你必须知道的话,我在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") )

给宝宝他的瓶子!

3 个答案:

答案 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中,这是以另一种方式实现的,结果相同 - 参数内的标识符名称不能引用被调用函数中的或标识符。

在解释其他两个问题之后,我还会谈到其他一些与名字相关的要点。

0-arity功能:()=>类型

语法() => Type代表Function0的类型。也就是说,一个不带参数并返回一些东西的函数。这相当于调用方法size() - 它不带参数并返回一个数字。

然而,有趣的是,这种语法与匿名函数文字的语法非常相似,这是造成一些混淆的原因。例如,

() => println("I'm an anonymous function")

是arity 0的匿名函数文字,其类型

() => Unit

所以我们可以写:

val f: () => Unit = () => println("I'm an anonymous function")

然而,重要的是不要将类型与值混淆。

单位=>类型

这实际上只是Function1,其第一个参数是Unit类型。其他撰写方式可能是(Unit) => TypeFunction1[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)