scala 闭包问题

scala 的三个函数如下所示,正确调用三个函数返回的函数签名是一样的,但是不明白三个函数不同之处到底代表什么?

直观上看 f1 和 f3 都是不接受任何参数,但是使用上 f1 可以使用省略括号和使用空括号两种方式,f3 则不能使用空括号。f1 和 f3 两个函数有什么区别呢?这种区别是 scala 的特性呢还是bug呢?

f1 和 f2 函数体内返回 pp 函数的时候使用不使用 “_“ 都是返回了函数。不使用 "_" 也并没有当成函数调用去编译然后报错。请问这个该怎么理解呢?

def f1(): String => Unit = {
  def pp(s: String): Unit = println(s)
  pp
}

def f2(): String => Unit = {
  def pp(s: String): Unit = println(s)
  pp _
}

def f3: String => Unit = {
  def pp(s: String): Unit = println(s)
  pp
}
阅读 3.4k
2 个回答

首先,要明确在 Scala 中如果一个方法不接受参数,那么可以不使用 () 调用它:

scala> 2.toString()
res1: String = 2

等价于:

scala> 2.toString

但是在定义函数时,方法是否有括号则很重要。对于楼主的函数:

def f1(): String => Unit = {
  def pp(s: String): Unit = println(s)
  pp
}

def f3: String => Unit = {
  def pp(s: String): Unit = println(s)
  pp
}

编译器认为 f1f3 不等价。对于 f1 我们可以不加括号调用它,也可以加上括号;但是 f3 就一定不能加上括号。这是一个 feature 而不是 bug可以参考我的这篇文章:有括号方法和无括号方法区别。在结构类型(Structural Type)中,这两者定义是有区别的。

再谈谈 f1f2 的区别。实际上 f1 返回的函数是 ppf2 返回的是一个匿名函数,这样匿名函数其实是:

s => pp(s)

这就是 _ 的作用。它实际上是一个占位符,表示接受一个参数。楼主也可以写成:

def f2(): String => Unit = {
  def pp(s: String): Unit = println(s)
  pp(_)  // 返回一个匿名函数,而不是 pp 了
}

回到楼主的例子中:

val c = b _

就等价于:

val c = () => b

另外,这三个函数在我理解看来不是闭包哦。闭包可以理解为在函数中引用了函数外部的变量,

没人回答就自问自答吧。
_ 我感觉就是个包装器,类似于

def f(s:String)(r:String) = println(s"$s passed, and then $r passed")

val a = f("hello") _

就相当于

val a = (r:String) => f("hello")(r)

对于 val b = 4 使用 val c = b _ 也会使得c成为一个匿名函数,函数签名为 ()=>Int
但是具体的机制怎么样还没弄明白。。。
对于函数 f3,是关于 pp 的使用,pp 编译器怎么编译 pp 取决于 pp 出现的位置。pp 首先是一个对象,function1 之类的对象。有些地方会把 pp 当作函数调用,有些地方会把 pp 当作 函数对象。

这两天写代码的一些感想,不严格。。。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进