什么是Scala中的命名函数?

4

我对“命名函数”感到困惑。

我们使用def定义一个方法,该方法的名称紧随其后。

例如:def m() = () => () 我们可以说这个方法的名称是m。 “命名方法”很容易理解,我相信没有匿名方法。

我在各处看到“匿名函数”的解释。 我知道匿名函数是函数类型的实例,并且我们可以轻松地找到匿名函数的示例。

那么,命名函数也必须是函数类型的实例。

我在这里尝试给出一个例子。 例如:val f = () => () 我认为这个函数的名称是f。 因此,在这里有一个命名函数。

但是,当我使用JD-GUI工具反编译类文件时,对我而言,f不是名字,而是一个ObjectRef

“命名函数”的概念有意义吗? 我完全搞糊涂了。


1
你在什么情境下遇到了“命名函数”这个短语? - Andrey Tyukin
我不清楚你的困惑是什么。你是否不理解函数值的工作原理? - Yuval Itzchakov
3
在Scala语言规范的第6.20节“Return表达式”中,它说:“一个return表达式return e必须出现在某个封闭的具名方法或函数的主体内。”我认为这里特别使用了“named”,以强调该方法或函数必须有名称。 - 汪李之
1
@汪李之:不幸的是,SLS在术语上有些宽泛,有时指函数对象,有时指方法,有时同时指两者。 - Jörg W Mittag
@JörgWMittag 谢谢。在Scala中,没有所谓的“命名函数”。函数从来没有名称。这对我很有帮助。事实上,我也想到了同样的想法,“函数从来没有名称”。只是我无法确认它。 - 汪李之
显示剩余2条评论
2个回答

1
我认为“命名函数”是指使用“def”关键字定义的嵌套函数,例如。考虑以下例子,这里就有区别了:
def foo: Int = {
  val f: Int => Int = x => return x
  f(58)
  42
}

println(foo) // returns 58

这里的x => return x部分是匿名函数文本的主体。函数文本被赋值给名称为f的变量并不影响return语句:当到达return时,整个方法foo返回。在这种情况下,它返回58,而42永远不会被执行。
然而,对于一个命名的嵌套函数,情况就不同了:
def bar: Int = {
  def f(x: Int): Int = {
    return x
  }
  f(58)
  42
}

println(bar) // returns 42

这里,return 只返回嵌套函数 f,而不是整个 bar 方法。语句位置的表达式 f(58) 求值为 58,然后被忽略。方法 bar 然后返回 42
在这种情况下,“function”比“method”更有意义。例如,嵌套函数 f 实际上与除了包含 bar 的类之外的某些类没有关联,并且它不能在包含方法 bar 的类的实例上调用,因此可能更适合将其称为“function”,而不是“method”。

f 不是一个函数,它是一个方法。 - Yuval Itzchakov
1
@YuvalItzchakov 很有趣,2008 年的 Scala 指南 将其称为“嵌套函数”。而 当前版本的 Scala 指南 将其称为“嵌套方法”。我个人更喜欢叫它“嵌套函数”,因为我没有看到任何可以在其上调用 f 的对象,但如果当前的官方指南是将其称为“嵌套方法”,那我也没问题。 - Andrey Tyukin
这是一个有趣的想法,也许是正确的,但术语使用得很宽泛。也许方法是成员,但重载解析谈论的是函数,例如。方法类型与函数类型在这里并没有真正帮助。 - som-snytt

1
“命名函数”这个概念有意义吗?规范说明如下:“返回表达式 return e 必须出现在某个封闭的命名方法或函数体内。” 命名部分仅适用于方法,而不是函数。尽管正如@som-snytt所解释的那样,我们也可以有命名函数:
object A extends Function1[Int, Int]

将被视为命名函数。

编辑:

联系了Lightbend,就规范定义中“命名方法或函数”的部分收到了回复:

这是一个规范错误——它应该只说“方法”。不幸的是,在规范中存在一些关于“方法”和“函数”的混淆。在返回表达式的段落上面,可以看到scalprod方法被称为“函数”的实例。我将提交一个请求以澄清非本地返回周围的部分。

回答你的问题,你应该只把方法看作是返回表达式的作用域规则。


你能否详细说明一下这个语句的第二部分是什么意思?如果“named”部分只指方法,那么第二部分似乎是在说“返回表达式return e必须出现在某个封闭函数的主体内”。但我不确定如何解释这个问题,因为例如val c = { val f: Int => Int = { x => return x }; f(42) }会产生编译错误“return outside method definition”。第二部分语句中指的是哪些函数?这只是无意中使用了遗留术语“嵌套函数->嵌套方法”吗? - Andrey Tyukin
规范继续说:“匿名函数的apply方法不算作命名函数。”因此,这个答案可能不足够。 - som-snytt
@som-snytt,您认为规范在将“命名函数”和“命名方法”混合使用时存在问题吗?否则我无法理解它的意义。 - Yuval Itzchakov
这显然是一个命名函数 object X extends Function1[Int,Int] {...}。通常也是 case class 的伴生对象。但它是一个 apply 方法。我不知道是否因为这个原因他们在这里给了这个区别过大的重视。 - som-snytt
1
@som-snytt 伴生对象是一个命名函数?为什么这样说? - Yuval Itzchakov
X相同的意义,案例伴侣默认扩展了FunctionN。今天有一个PR来消除这种命名差异,所以历史(未来的历史)证明你是正确的。编辑:刚刚重新阅读了您的答案,加一。 - som-snytt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接