在 Scala 中定义函数的两种方式。有什么区别?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5009411/
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:49:09  来源:igfitidea点击:

Two ways of defining functions in Scala. What is the difference?

functionscalacurrying

提问by aioobe

Here is a little Scala session that defines and tries out some functions:

这是一个小的 Scala 会话,它定义并尝试了一些函数:

scala> def test1(str: String) = str + str;    
test1: (str: String)java.lang.String

scala> test1("ab")
res0: java.lang.String = abab

works nicely.

很好用。

scala> val test2 = test1
<console>:6: error: missing arguments for method test1 in object $iw;
follow this method with `_' if you want to treat it as a partially applied function
       val test2 = test1
                   ^

oops.

哎呀。

scala> val test2 = test1 _
test2: (String) => java.lang.String = <function1>

scala> test2("ab")
res1: java.lang.String = abab

works well!

效果很好!

Now, I've seen the _syntax when folding (_ + _, etc). So as I understand it _basically means "an argument". So test1 _basically means a function with an argument, which is given to test1". But why isn't that exactlythe same as just test1? Why is there a difference if I append a _?

现在,我已经看到了_折叠 (_ + _等)时的语法。所以据我所知,它_基本上意味着“争论”。所以test1 _基本上意味着一个带有参数的函数,它被赋予test1“。但为什么这与 just不完全一样test1?为什么如果我附加 a 会有区别_

So I kept exploring...

所以我一直在探索……

scala> val test3 = (str: String) => str + str
test3: (String) => java.lang.String = <function1>

scala> test3("ab")
res2: java.lang.String = abab

scala> val test4 = test3
test4: (String) => java.lang.String = <function1>

Here it works without _! What's the difference between a defed function, and a valed function?

在这里它没有_defed 函数和valed 函数有什么区别?

回答by axel22

The defdeclares a method within a surrounding object/class/trait, similar to the way you define methods in Java. You can only use defs within other objects/classes/traits. In the REPL, you cannot see the surrounding object because it's "hidden", but it does exist.

def声明周围物体/班/特质中的一个方法,类似于你定义的Java方法的方式。您只能def在其他对象/类/特征中使用s。在 REPL 中,您看不到周围的对象,因为它是“隐藏的”,但它确实存在。

You cannot assign a defto a value, because the defis not a value - it's a method in the object.

你不能给一个def值赋值,因为def它不是一个值——它是对象中的一个方法。

The (x: T) => x * xdeclares and instantiates a function object, which exists at runtime. Function objects are instances of anonymous classes which extend FunctionNtraits. FunctionNtraits come with an applymethod. The name applyis special, because it can be omitted. Expression f(x)is desugared into f.apply(x).

(x: T) => x * x声明并实例化一个函数对象,它存在在运行时。函数对象是扩展FunctionN特征的匿名类的实例。FunctionN特质伴随着一种apply方法。这个名字apply很特别,因为它可以省略。表达式f(x)脱糖为f.apply(x).

The bottomline is - since function objects are runtime values which exist on the heap, you can assign them to values, variables and parameters, or return them from methods as return values.

底线是 - 由于函数对象是存在于堆上的运行时值,您可以将它们分配给值、变量和参数,或者从方法中将它们作为返回值返回。

To solve the issue of assigning methods to values (which can be useful), Scala allows you to use the placeholder character to create a function object from a method. Expression test1 _in your example above actually creates a wrapper function around the method test1- it is equivalent to x => test1(x).

为了解决将方法分配给值的问题(这很有用),Scala 允许您使用占位符字符从方法创建函数对象。test1 _上面示例中的表达式实际上在该方法周围创建了一个包装函数test1- 它等效于x => test1(x).

回答by Daniel C. Sobral

There's no difference between a def'ed function and a val'ed function:

def'ed 函数和 val'ed 函数之间没有区别:

scala> def test1 = (str: String) => str + str
test1: (String) => java.lang.String

scala> val test2 = test1
test2: (String) => java.lang.String = <function1>

scala> val test3 = (str: String) => str + str
test3: (String) => java.lang.String = <function1>

scala> val test4 = test2
test4: (String) => java.lang.String = <function1>

See? All of these are functions, which is indicated by the X => Ytype they have.

看?所有这些都是函数,由X => Y它们的类型表示。

scala> def test5(str: String) = str + str
test5: (str: String)java.lang.String

Do you see an X => Ytype? If you do, go see an ophthalmologist, because there's none. The type here is (X)Y, commonly used to denote a method.

你看到一个X => Y类型吗?如果你这样做,去看眼科医生,因为没有。这里的类型是(X)Y,通常用来表示一个方法

Actually, test1, test2, test3and test4are all methods, which return functions. test5is a method which returns a java.lang.String. Also, test1through test4do not take parameters (only test1could, anyway), while test5does.

实际上,test1, test2,test3test4都是返回函数的方法。test5是一种返回 a 的方法java.lang.String。此外,test1throughtest4不带参数(test1无论如何只能),而 whiletest5是。

So, the difference is pretty simple. In the first case, you tried to assign a method to a val, but did not fill in the parameters the method take. So it failed, until you added a trailing underscore, which meant turn my method into a function.

所以,区别很简单。在第一种情况下,您尝试将一个方法分配给一个 val,但没有填写该方法采用的参数。所以它失败了,直到你添加了一个尾随下划线,这意味着把我的方法变成一个函数

In the second example you had a function, so you didn't need to do anything else.

在第二个示例中,您有一个函数,因此您无需执行任何其他操作。

A method is not a function, and vice versa. A function is an object of one of the FunctionNclasses. A method is a handle to some piece of code associated with an object.

方法不是函数,反之亦然。函数是其中一个FunctionN类的对象。方法是与对象关联的某些代码段的句柄。

See various questions about methods vs functions on Stack Overflow.

在 Stack Overflow 上查看有关方法与函数的各种问题。

回答by Synesso

The underscore means different things in different contexts. But it can always be thought of as the thing that would go here, but doesn't need to be named.

下划线在不同的上下文中意味着不同的东西。但它总是可以被认为是会去这里的东西,但不需要命名

When applied in place of parameters, the effect is to lift the method to a function.

当代替参数应用时,效果是将方法提升为函数。

scala> def test1(str: String) = str + str; 
test1: (str: String)java.lang.String

scala> val f1 = test1 _
f1: (String) => java.lang.String = <function1>

Note, the method has become a function of type (String) => String.

请注意,该方法已成为类型为 (String) => String 的函数。

The distinction between a method and a function in Scala is that methods are akin to traditional Java methods. You can't pass them around as values. However functions are values in their own right and can be used as input parameters and return values.

Scala 中方法和函数的区别在于方法类似于传统的 Java 方法。您不能将它们作为值传递。然而,函数本身就是值,可以用作输入参数和返回值。

The lifting can go further:

提升可以更进一步:

scala> val f2 = f1 _
f2: () => (String) => java.lang.String = <function0>

Lifting this function results in another function. This time of type () => (String) => (String)

提升这个函数会导致另一个函数。这次的类型 () => (String) => (String)

From what I can tell, this syntax is equivalent to substituting all of the parameters with an underscore explicitly. For example:

据我所知,此语法等效于用下划线显式替换所有参数。例如:

scala> def add(i: Int, j: Int) = i + j
add: (i: Int,j: Int)Int

scala> val addF = add(_, _)
addF: (Int, Int) => Int = <function2>

scala> val addF2 = add _    
addF2: (Int, Int) => Int = <function2>