scala Scala中方法和函数的区别

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2529184/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 02:01:58  来源:igfitidea点击:

Difference between method and function in Scala

functionscalamethods

提问by Anantha Kumaran

I read Scala Functions(part of Another tour of Scala). In that post he stated:

我阅读了Scala 函数另一个 Scala 之旅的一部分)。在那个帖子中,他说:

Methods and functions are not the same thing

方法和函数不是一回事

But he didn't explain anything about it. What was he trying to say?

但他没有解释任何关于它的事情。他想说什么?

回答by Daniel C. Sobral

Jim has got this pretty much covered in his blog post, but I'm posting a briefing here for reference.

Jim 在他的博客文章中对此进行了大量介绍,但我在这里发布了一份简报以供参考。

First, let's see what the Scala Specification tell us. Chapter 3 (types) tell us about Function Types(3.2.9) and Method Types(3.3.1). Chapter 4 (basic declarations) speaks of Value Declaration and Definitions(4.1), Variable Declaration and Definitions(4.2) and Functions Declarations and Definitions(4.6). Chapter 6 (expressions) speaks of Anonymous Functions(6.23) and Method Values(6.7). Curiously, function values is spoken of one time on 3.2.9, and no where else.

首先,让我们看看 Scala 规范告诉我们什么。第 3 章(类型)告诉我们函数类型(3.2.9)和方法类型(3.3.1)。第 4 章(基本声明)讨论了值声明和定义(4.1)、变量声明和定义(4.2) 以及函数声明和定义(4.6)。第 6 章(表达式)谈到匿名函数(6.23)和方法值(6.7)。奇怪的是,函数值在 3.2.9 上被提到过一次,其他地方没有。

A Function Typeis (roughly) a type of the form (T1, ..., Tn) => U, which is a shorthand for the trait FunctionNin the standard library. Anonymous Functionsand Method Valueshave function types, and function types can be used as part of value, variable and function declarations and definitions. In fact, it can be part of a method type.

函数类型是(大约)的类型的形式(T1,...,TN)=>Ü,这对于该性状的简写FunctionN在标准库。匿名函数方法 值具有函数类型,函数类型可以用作值、变量和函数声明和定义的一部分。事实上,它可以是方法类型的一部分。

A Method Typeis a non-value type. That means there is novalue - no object, no instance - with a method type. As mentioned above, a Method Valueactually has a Function Type. A method type is a defdeclaration - everything about a defexcept its body.

方法类型是一个非值类型。这意味着没有值 - 没有对象,没有实例 - 具有方法类型。如上所述,一个方法值实际上有一个函数类型。方法类型是一个def声明——def除了它的主体之外的所有内容。

Value Declarations and Definitionsand Variable Declarations and Definitionsare valand vardeclarations, including both type and value- which can be, respectively, Function Typeand Anonymous Functions or Method Values. Note that, on the JVM, these (method values) are implemented with what Java calls "methods".

值声明和定义以及变量声明和定义valvar声明,包括类型和值——它们可以分别是函数类型匿名函数或方法值。请注意,在 JVM 上,这些(方法值)是通过 Java 所谓的“方法”实现的。

A Function Declarationis a defdeclaration, including typeand body. The type part is the Method Type, and the body is an expression or a block. This is also implemented on the JVM with what Java calls "methods".

函数声明是一个def声明,包括类型身体。类型部分是方法类型,主体是表达式或块。这也是在 JVM 上使用 Java 所谓的“方法”实现的。

Finally, an Anonymous Functionis an instance of a Function Type(ie, an instance of the trait FunctionN), and a Method Valueis the same thing! The distinction is that a Method Value is created from methods, either by postfixing an underscore (m _is a method value corresponding to the "function declaration" (def) m), or by a process called eta-expansion, which is like an automatic cast from method to function.

最后,匿名函数函数类型的实例(即 trait 的实例FunctionN),和方法值是一回事!区别在于,方法值是从方法创建的,要么通过后缀下划线(m _是对应于“函数声明”的方法值 ( def) m),要么通过称为eta-expansion的过程创建,就像从方法自动转换发挥作用。

That is what the specs say, so let me put this up-front: we do not use that terminology!It leads to too much confusion between so-called "function declaration", which is a part of the program (chapter 4 -- basic declarations) and "anonymous function", which is an expression, and "function type", which is, well a type -- a trait.

这就是规范所说的,所以让我提前说明:我们不使用该术语!它导致所谓的“函数声明”(程序的一部分(第 4 章——基本声明))和“匿名函数”(表达式)和“函数类型”(即,好吧,一种类型——一种特质。

The terminology below, and used by experienced Scala programmers, makes one change from the terminology of the specification: instead of saying function declaration, we say method. Or even method declaration. Furthermore, we note that value declarationsand variable declarationsare also methods for practical purposes.

下面的术语由有经验的 Scala 程序员使用,对规范的术语做了一个更改:我们说方法声明而不是函数声明。甚至方法声明。此外,我们注意到值声明变量声明也是用于实际目的的方法。

So, given the above change in terminology, here's a practical explanation of the distinction.

因此,鉴于上述术语的变化,以下是对区别的实际解释。

A functionis an object that includes one of the FunctionXtraits, such as Function0, Function1, Function2, etc. It might be including PartialFunctionas well, which actually extends Function1.

函数是一个对象,包括所述的一个FunctionX特征,诸如Function0Function1Function2等。它可以被包括PartialFunction为好,这实际上延伸Function1

Let's see the type signature for one of these traits:

让我们看看这些特征之一的类型签名:

trait Function2[-T1, -T2, +R] extends AnyRef

This trait has one abstract method (it has a few concrete methods as well):

这个 trait 有一个抽象方法(它也有一些具体的方法):

def apply(v1: T1, v2: T2): R

And that tell us all that there is to know about it. A functionhas an applymethod which receives Nparameters of types T1, T2, ..., TN, and returns something of type R. It is contra-variant on the parameters it receives, and co-variant on the result.

这告诉我们所有需要了解的信息。一个函数有一个apply方法,它接收N个类型为T1T2、...、TN 的参数,并返回一些类型的参数R。它在接收到的参数上是逆变的,在结果上是协变的。

That variance means that a Function1[Seq[T], String]is a subtype of Function1[List[T], AnyRef]. Being a subtype means it can be used in place ofit. One can easily see that if I'm going to call f(List(1, 2, 3))and expect an AnyRefback, either of the two types above would work.

这种差异意味着 aFunction1[Seq[T], String]是 的子类型Function1[List[T], AnyRef]。作为子类型意味着它可以代替它使用。人们可以很容易地看到,如果我要打电话f(List(1, 2, 3))并期望得到AnyRef回报,上述两种类型中的任何一种都可以。

Now, what is the similarityof a method and a function? Well, if fis a function and mis a method local to the scope, then both can be called like this:

现在,方法和函数的相似之处是什么?好吧,如果f是一个函数并且m是作用域的局部方法,那么两者都可以这样调用:

val o1 = f(List(1, 2, 3))
val o2 = m(List(1, 2, 3))

These calls are actually different, because the first one is just a syntactic sugar. Scala expands it to:

这些调用实际上是不同的,因为第一个调用只是一个语法糖。Scala 将其扩展为:

val o1 = f.apply(List(1, 2, 3))

Which, of course, is a method call on object f. Functions also have other syntactic sugars to its advantage: function literals (two of them, actually) and (T1, T2) => Rtype signatures. For example:

当然,这是对 object 的方法调用f。函数还有其他语法糖来发挥它的优势:函数文字(实际上是其中两个)和(T1, T2) => R类型签名。例如:

val f = (l: List[Int]) => l mkString ""
val g: (AnyVal) => String = {
  case i: Int => "Int"
  case d: Double => "Double"
  case o => "Other"
}

Another similarity between a method and a function is that the former can be easily converted into the latter:

方法和函数之间的另一个相似之处是前者可以很容易地转换为后者:

val f = m _

Scala will expand that, assuming mtype is (List[Int])AnyRefinto (Scala 2.7):

Scala 将扩展that,假设m类型(List[Int])AnyRef为(Scala 2.7):

val f = new AnyRef with Function1[List[Int], AnyRef] {
  def apply(x: List[Int]) = this.m(x)
}

On Scala 2.8, it actually uses an AbstractFunction1class to reduce class sizes.

在 Scala 2.8 上,它实际上使用一个AbstractFunction1类来减少类的大小。

Notice that one can't convert the other way around -- from a function to a method.

请注意,不能以相反的方式转换——从函数到方法。

Methods, however, have one big advantage (well, two -- they can be slightly faster): they can receive type parameters. For instance, while fabove can necessarily specify the type of Listit receives (List[Int]in the example), mcan parameterize it:

然而,方法有一个很大的优势(好吧,两个——它们可以稍微快一点):它们可以接收类型参数。例如,虽然f上面必须指定List它接收的类型(List[Int]在示例中),但m可以对其进行参数化:

def m[T](l: List[T]): String = l mkString ""

I think this pretty much covers everything, but I'll be happy to complement this with answers to any questions that may remain.

我认为这几乎涵盖了所有内容,但我很乐意通过回答可能存在的任何问题来补充这一点。

回答by Ben Lings

One big practical difference between a method and a function is what returnmeans. returnonly ever returns from a method. For example:

方法和函数之间的一个很大的实际区别是什么return意思。 return只从一个方法返回。例如:

scala> val f = () => { return "test" }
<console>:4: error: return outside method definition
       val f = () => { return "test" }
                       ^

Returning from a function defined in a method does a non-local return:

从方法中定义的函数返回会执行非本地返回:

scala> def f: String = {                 
     |    val g = () => { return "test" }
     | g()                               
     | "not this"
     | }
f: String

scala> f
res4: String = test

Whereas returning from a local method only returns from that method.

而从本地方法返回仅从该方法返回。

scala> def f2: String = {         
     | def g(): String = { return "test" }
     | g()
     | "is this"
     | }
f2: String

scala> f2
res5: String = is this

回答by jamlhet

functionA function can be invoked with a list of arguments to produce a result. A function has a parameter list, a body, and a result type. Functions that are members of a class, trait, or singleton object are called methods. Functions defined inside other functions are called local functions. Functions with the result type of Unit are called procedures. Anonymous functions in source code are called function literals. At run time, function literals are instantiated into objects called function values.

函数可以使用参数列表调用函数以产生结果。一个函数有一个参数列表、一个函数体和一个结果类型。作为类、特征或单例对象成员的函数称为方法。在其他函数内部定义的函数称为局部函数。结果类型为 Unit 的函数称为过程。源代码中的匿名函数称为函数字面量。在运行时,函数文字被实例化为称为函数值的对象。

Programming in Scala Second Edition. Martin Odersky - Lex Spoon - Bill Venners

Scala 第二版编程。Martin Odersky - Lex Spoon - Bill Venners

回答by anish

Let Say you have a List

假设你有一个列表

scala> val x =List.range(10,20)
x: List[Int] = List(10, 11, 12, 13, 14, 15, 16, 17, 18, 19)

Define a Method

定义方法

scala> def m1(i:Int)=i+2
m1: (i: Int)Int

Define a Function

定义函数

scala> (i:Int)=>i+2
res0: Int => Int = <function1>

scala> x.map((x)=>x+2)
res2: List[Int] = List(12, 13, 14, 15, 16, 17, 18, 19, 20, 21)

Method Accepting Argument

方法接受参数

scala> m1(2)
res3: Int = 4

Defining Function with val

用 val 定义函数

scala> val p =(i:Int)=>i+2
p: Int => Int = <function1>

Argument to function is Optional

函数的参数是可选的

 scala> p(2)
    res4: Int = 4

scala> p
res5: Int => Int = <function1>

Argument to Method is Mandatory

方法论据是强制性的

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

Check the following Tutorialthat explains passing other differences with examples like other example of diff with Method Vs Function, Using function as Variables, creating function that returned function

检查以下教程,该教程解释了通过示例传递其他差异,例如使用方法与函数的其他差异示例,将函数用作变量,创建返回函数的函数

回答by eptx

Functions don't support parameter defaults. Methods do. Converting from a method to a function loses parameter defaults. (Scala 2.8.1)

函数不支持参数默认值。方法做。从方法转换为函数会丢失参数默认值。(斯卡拉 2.8.1)

回答by Mehran

There is a nice article herefrom which most of my descriptions are taken. Just a short comparison of Functions and Methods regarding my understanding. Hope it helps:

有一个很好的文章在这里从我的大部分描述都采取。只是关于我的理解的函数和方法的简短比较。希望能帮助到你:

Functions: They are basically an object. More precisely, functions are objects with an apply method; Therefore, they are a little bit slower than methods because of their overhead. It is similar to static methods in the sense that they are independent of an object to be invoked. A simple example of a function is just like bellow:

函数:它们基本上是一个对象。更准确地说,函数是具有 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 = )

除了将一个对象分配给另一个对象(例如 object1 = object2)之外,上面的行什么也没有。实际上,我们示例中的 object2 是一个匿名函数,因此左侧获取对象的类型。因此,现在 f1 是一个对象(函数)。匿名函数实际上是 Function1[Int, Int] 的一个实例,这意味着一个具有 1 个 Int 类型参数和 Int 类型返回值的函数。不带参数调用 f1 将为我们提供匿名函数的签名 (Int => Int = )

Methods: They are not objects but assigned to an instance of a class,i.e., an object. Exactly the same as method in java or member functions in c++ (as Raffi Khatchadourianpointed out in a comment to this question) and etc. A simple example of a method is just like bellow:

方法:它们不是对象,而是分配给类的实例,即对象。与 java 中的方法或 c++ 中的成员函数完全相同(如Raffi Khatchadourian对该问题的评论中指出的)等。一个简单的方法示例如下所示:

def m1(x: Int) = x + x
m1(2)  // 4

The line above is not a simple value assignment but a definition of a method. When you invoke this method with the value 2 like the second line, the x is substituted with 2 and the result will be calculated and you get 4 as an output. Here you will get an error if just simply write m1 because it is method and need the input value. By using _ you can assign a method to a function like bellow:

上面这行不是简单的赋值,而是一个方法的定义。当您像第二行一样使用值 2 调用此方法时,x 将被替换为 2,并且将计算结果并获得 4 作为输出。如果只是简单地写 m1 ,你会得到一个错误,因为它是方法并且需要输入值。通过使用 _,您可以将方法分配给如下所示的函数:

val f2 = m1 _  // Int => Int = <function1>

回答by Valy Dia

Here is a great postby Rob Norris which explains the difference, here is a TL;DR

这是Rob Norris 的一篇很棒的文章,它解释了差异,这是一个 TL;DR

Methods in Scala are not values, but functions are. You can construct a function that delegates to a method via η-expansion (triggered by the trailing underscore thingy).

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

with the following definition:

具有以下定义:

a methodis something defined with defand a valueis something you can assign to a val

一个方法是定义什么DEF是你可以分配给VAL

In a nutshell (extract from the blog):

简而言之(摘自博客):

When we define a method we see that we cannot assign it to a val.

当我们定义一个方法时,我们看到我们不能将它分配给 a 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

Note also the typeof add1, which doesn't look normal; you can't declare a variable of type (n: Int)Int. Methods are not values.

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

However, by adding the η-expansion postfix operator (η is pronounced “eta”), we can turn the method into a function value. Note the type of f.

但是,通过添加 η 扩展后缀运算符(η 发音为“eta”),我们可以将方法转换为函数值。注意 的类型f

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

scala> f(3)
res0: Int = 4

The effect of _is to perform the equivalent of the following: we construct a Function1instance that delegates to our method.

的效果_是执行以下等效操作:我们构造一个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

回答by Mario Galic

In Scala 2.13, unlike functions, methods can take/return

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

  • type parameters (polymorphic methods)
  • implicit parameters
  • dependent types
  • 类型参数(多态方法)
  • 隐式参数
  • 依赖类型

However, these restrictions are lifted in dotty (Scala 3) by Polymorphic function types #4672, for example, dotty version 0.23.0-RC1enables the following syntax

但是,这些限制在 dotty (Scala 3) 中被Polymorphic function types #4672解除,例如,dotty版本0.23.0-RC1启用以下语法

Type parameters

类型参数

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

Implicit parameters (contextparameters)

隐式参数(上下文参数)

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

Dependent types

依赖类型

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

For more examples, see tests/run/polymorphic-functions.scala

有关更多示例,请参阅tests/run/polymorphic-functions.scala

回答by Ying

Practically, a Scala programmer only needs to know the following three rules to use functions and methods properly:

实际上,Scala 程序员只需要知道以下三个规则即可正确使用函数和方法:

  • Methods defined by defand function literals defined by =>are functions. It is defined in page 143, Chapter 8 in the book of Programming in Scala, 4th edition.
  • Function values are objects that can be passed around as any values. Function literals and partially applied functions are function values.
  • You can leave off the underscore of a partially applied function if a function value is required at a point in the code. For example: someNumber.foreach(println)
  • 由定义的方法def和由定义的函数文字=>是函数。它在《Scala 编程》第 4 版一书中的第 8 章第 143 页中定义。
  • 函数值是可以作为任何值传递的对象。函数文字和部分应用的函数是函数值。
  • 如果代码中的某个点需要函数值,则可以省略部分应用函数的下划线。例如:someNumber.foreach(println)

After four editions of Programming in Scala, it is still an issue for people to differentiate the two important concepts: function and function value because all editions don't give a clear explanation. The language specification is too complicated. I found the above rules are simple and accurate.

《Programming in Scala》四个版本之后,对于函数和函数值这两个重要概念的区分仍然是一个问题,因为所有版本都没有给出明确的解释。语言规范太复杂了。我发现上述规则既简单又准确。