我读过Scala函数(Scala另一个指南的一部分)。在那篇帖子中,他说:
方法和函数不是一回事
但他什么也没解释。他到底想说什么?
我读过Scala函数(Scala另一个指南的一部分)。在那篇帖子中,他说:
方法和函数不是一回事
但他什么也没解释。他到底想说什么?
当前回答
这里有一篇不错的文章,我的大部分描述都来自于它。 关于我的理解,只是一个简短的函数和方法的比较。希望能有所帮助:
功能: 它们基本上是一个物体。更准确地说,函数是具有apply方法的对象;因此,由于开销,它们比方法要慢一些。它类似于静态方法,因为它们独立于要调用的对象。 一个简单的函数示例如下所示:
val f1 = (x: Int) => x + x
f1(2) // 4
The line above is nothing except assigning one object to another like object1 = object2. Actually the object2 in our example is an anonymous function and the left side gets the type of an object because of that. Therefore, now f1 is an object(Function). The anonymous function is actually an instance of Function1[Int, Int] that means a function with 1 parameter of type Int and return value of type Int. Calling f1 without the arguments will give us the signature of the anonymous function (Int => Int = )
方法: 它们不是对象,而是赋值给类的实例。,一个物体。与java中的方法或c++中的成员函数完全相同(正如Raffi Khatchadourian在对这个问题的评论中指出的那样)等等。 一个简单的方法示例如下所示:
def m1(x: Int) = x + x
m1(2) // 4
上面这一行不是简单的值赋值,而是方法的定义。当您像第二行一样使用值2调用此方法时,x被替换为2,结果将被计算出来,并得到4作为输出。在这里,如果只是简单地写m1,就会得到一个错误,因为它是一个方法,需要输入值。通过使用_,你可以将一个方法分配给一个函数,如下所示:
val f2 = m1 _ // Int => Int = <function1>
其他回答
在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
区别是细微的,但却是实质性的,它与所使用的类型系统有关(除了来自面向对象或函数范式的术语)。
当我们谈论函数时,我们谈论的是函数类型:它是一种类型,它的实例可以作为输入或输出传递给其他函数(至少在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程序员只需要知道以下三条规则就可以正确使用函数和方法:
由def定义的方法和由=>定义的函数字面量是函数。在《Programming in Scala》第4版第8章第143页中定义。 函数值是可以作为任何值传递的对象。函数字面量和部分应用的函数是函数值。 如果在代码中的某个位置需要函数值,则可以省略部分应用的函数的下划线。例如:someNumber.foreach(println)
在《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时,它会自动将该方法转换为等效的函数。