我读过Scala函数(Scala另一个指南的一部分)。在那篇帖子中,他说:
方法和函数不是一回事
但他什么也没解释。他到底想说什么?
我读过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中是这样)。
当我们谈论(类的)方法时,我们实际上是在谈论它所属的类所表示的类型:也就是说,方法只是更大类型的一个组件,不能单独传递。它必须与它所属类型的实例(即类的实例)一起传递。