我读过Scala函数(Scala另一个指南的一部分)。在那篇帖子中,他说:

方法和函数不是一回事

但他什么也没解释。他到底想说什么?


当前回答

区别是细微的,但却是实质性的,它与所使用的类型系统有关(除了来自面向对象或函数范式的术语)。

当我们谈论函数时,我们谈论的是函数类型:它是一种类型,它的实例可以作为输入或输出传递给其他函数(至少在Scala中是这样)。

当我们谈论(类的)方法时,我们实际上是在谈论它所属的类所表示的类型:也就是说,方法只是更大类型的一个组件,不能单独传递。它必须与它所属类型的实例(即类的实例)一起传递。

其他回答

这是Rob Norris写的一篇很棒的文章,解释了两者的区别

Scala中的方法不是值,但函数是。您可以构造一个通过η扩展(由后面的下划线触发)委托给某个方法的函数。

定义如下:

方法是用def定义的东西,值是可以赋值给val的东西

简而言之(摘自博客):

定义方法时,我们发现不能将其赋值给val。

scala> def add1(n: Int): Int = n + 1
add1: (n: Int)Int

scala> val f = add1
<console>:8: error: missing arguments for method add1;
follow this method with `_' if you want to treat it as a partially applied function
       val f = add1

还要注意add1的类型,它看起来不正常;你不能声明一个(n: Int)Int类型的变量。方法不是值。

然而,通过添加η扩展后加算符(η读作“eta”),我们可以将该方法转化为函数值。注意f的类型。

scala> val f = add1 _
f: Int => Int = <function1>

scala> f(3)
res0: Int = 4

_的效果相当于执行以下操作:我们构造一个Function1实例,委托给我们的方法。

scala> val g = new Function1[Int, Int] { def apply(n: Int): Int = add1(n) }
g: Int => Int = <function1>

scala> g(3)
res18: Int = 4

函数不支持默认参数。做的方法。从方法转换到函数会丢失参数默认值。(Scala 2.8.1发布)

在Scala 2.13中,与函数不同,方法可以接受/返回

类型参数(多态方法) 隐式参数 从属类型

然而,这些限制在dotty (Scala 3)中通过多态函数类型#4672解除了,例如,dotty版本0.23.0-RC1支持以下语法

类型参数

def fmet[T](x: List[T]) = x.map(e => (e, e))
val ffun = [T] => (x: List[T]) => x.map(e => (e, e))

隐式参数(上下文参数)

def gmet[T](implicit num: Numeric[T]): T = num.zero
val gfun: [T] => Numeric[T] ?=> T = [T] => (using num: Numeric[T]) => num.zero

从属类型

class A { class B }
def hmet(a: A): a.B = new a.B
val hfun: (a: A) => a.B = hmet

更多示例请参见tests/run/ polymorphism -functions.scala

方法属于一个对象(通常是定义它的类、trait或对象),而函数本身是一个值,因为在Scala中每个值都是一个对象,因此,函数是一个对象。

例如,给定下面的方法和函数:

def timesTwoMethod(x :Int): Int = x * 2
def timesTwoFunction = (x: Int) => x * 2

第二个def是Int => Int类型的对象(Function1[Int, Int]的语法糖)。

Scala将函数作为对象,这样它们就可以作为一级实体使用。通过这种方式,可以将函数作为参数传递给其他函数。

然而,Scala也可以通过一种称为Eta展开的机制将方法视为函数。

例如,定义在List上的高阶函数映射,接收另一个函数f: A => B作为其唯一参数。接下来的两行是等价的:

List(1, 2, 3).map(timesTwoMethod)
List(1, 2, 3).map(timesTwoFunction)

当编译器在需要函数的地方看到def时,它会自动将该方法转换为等效的函数。

区别是细微的,但却是实质性的,它与所使用的类型系统有关(除了来自面向对象或函数范式的术语)。

当我们谈论函数时,我们谈论的是函数类型:它是一种类型,它的实例可以作为输入或输出传递给其他函数(至少在Scala中是这样)。

当我们谈论(类的)方法时,我们实际上是在谈论它所属的类所表示的类型:也就是说,方法只是更大类型的一个组件,不能单独传递。它必须与它所属类型的实例(即类的实例)一起传递。