首页 > 解决方案 > 一个函数如何是一个值,而一个方法 ID 不是?

问题描述

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

标签: scala

解决方案


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

方法绑定到对象。让方法既是对象的构建块又是对象本身是很尴尬的。让它们不是对象更容易。

在某种意义上,Scala 中的函数只是一个带有apply方法的对象。如果没有foo在作用域中命名的方法,那么foo()就是foo.apply(). 因此,函数是值,因为它们是对象。

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

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

是语法糖

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

函数类型

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

是语法糖

type F = Function3[Int, String, Long, Boolean]

[斯卡斯蒂链接]

每个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>"
}

等等。

可以使用η-expansion将方法转换为函数值。这可以使用尾随下划线显式完成:

val f = println _

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

val it = Iterable(1, 2, 3)

it.foreach(println)

[斯卡斯蒂链接]

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

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

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


推荐阅读