scala - 为什么函数是值,而方法 id 不是?

标签 scala

为什么函数是值而方法不是,或者是什么让函数成为值?什么可以让我破译方法不包含该特征?

最佳答案

Scala 是一种面向对象的语言。在面向对象语言中,每个值都是一个对象,每个对象也是一个值。

方法绑定(bind)到对象。让方法同时成为对象的构建 block 和对象本身是很尴尬的。让它们不成为对象会更容易。

从某种意义上说,Scala 中的函数只是一个具有 apply 方法的对象。如果范围内没有名为 foo 的方法,则 foo() is simply syntactic sugar for foo.apply() 。因此,函数之所以是值,是因为它们是对象。

虽然任何具有 apply 方法的对象都可以像函数一样被调用,但当我们在 Scala 中谈论“函数”时,我们通常意味着更多的东西具体: FunctionN 之一的实例特征如Function2[-T1, -T2, +R] 。特别是,函数文字语法

val add = (a: Int, b: Int) => a + b

is syntactic sugar for

val add = new Function2[Int, Int, Int] {
  override def apply(a: Int, b: Int) = a + b
}

还有function type

type F = (Int, String, Long) => Boolean

的语法糖
type F = Function3[Int, String, Long, Boolean]

[Scastie link]

其中每个 FunctionN 特征的定义如下:

package scala

trait Function0[+R] {
  def apply: R
  override def toString = "<function>"
}

trait Function1[-T, +R] {
  def apply(x: T): R
  override def toString = "<function>"
}

trait Function2[-T1, -T2, +R] {
  def apply(x1: T1, x2: T2): R
  override def toString = "<function>"
}

trait Function3[-T1, -T2, -T3, +R] {
  def apply(x1: T1, x2: T2, x3: T3): R
  override def toString = "<function>"
}

等等。

可以convert a method into a function value使用η-expansion 。这可以使用尾随下划线显式完成:

val f = println _

或者在某些情况下,当很明显需要函数值时,即使只使用方法的裸名称:

val it = Iterable(1, 2, 3)

it.foreach(println)

[Scastie link]

请注意,这与其他语言没有太大区别。例如,在 Java、C# 和 Ruby 中,情况是一样的:方法被定义为类(或 C# 中的结构和 Ruby 中的模块)的一部分,并且绑定(bind)到对象,但它们本身并不是对象。相反,您有一个单独的函数概念(Java 中的 SAM 接口(interface)/功能接口(interface)实例、C# 中的 ActionFuncProc在 Ruby 中),它是一个对象。

在 Ruby 中,您可以为绑定(bind)到与 Proc 具有相同接口(interface)的对象的方法创建代理对象。

其他语言做出了不同的选择,即在 ECMAScript 和 Python 中,方法对象/值,但它们不像 Scala、Java、C# 和 Ruby 那样与对象紧密绑定(bind)。相反,方法基本上是分配给对象字段的普通函数。

关于scala - 为什么函数是值,而方法 id 不是?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62252045/

相关文章:

Scala 将子类与参数匹配

scala - 为什么 Scala 的库在 2.7 和 2.8 之间增加了一倍?

scala - 将Spark的DataFrame转换为RDD[Vector]

scala - 如何使用Scala解压缩简明的(hadoop文件格式)文件

scala - 与 Scala 中的存在类型混淆

Emacs scala-mode 换行和缩进怪异

scala - 如何在 Scala 中没有早期初始化程序的情况下为父类(super class)构造函数创建参数

scala - 基于类的类型参数使用 Poly1 在方法中映射 HList

android - 如何排除 sbt-android-sdk 插件中的许可文件?

scala - HList 的通用解压