在 Scala 中定义函数的两种方法。有什么区别?
这是一个定义并尝试一些功能的 Scala 会话:
scala> def test1(str: String) = str + str;
test1: (str: String)java.lang.String
scala> test1("ab")
res0: java.lang.String = abab
效果很好。
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
^
哎呀。
scala> val test2 = test1 _
test2: (String) => java.lang.String = <function1>
scala> test2("ab")
res1: java.lang.String = abab
效果很好!
现在,我已经看到了折叠时的 _
语法(_ + _
等)。据我了解, _
基本上意味着“一个论点”。所以 test1 _
基本上意味着一个带有参数的函数,该函数被赋予 test1
”。但是为什么这不完全与刚才的相同test1
?为什么如果我附加一个_
会有区别?
所以我一直在探索......
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>
这里没有_
有什么区别!在 def
ed 函数和 val
ed 函数之间?
Here is a little Scala session that defines and tries out some functions:
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 exactly the same as just test1
? Why is there a difference if I append 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 def
ed function, and a val
ed function?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
def
在周围的对象/类/特征中声明一个方法,类似于在 Java 中定义方法的方式。您只能在其他对象/类/特征中使用def
。在 REPL 中,您看不到周围的对象,因为它是“隐藏的”,但它确实存在。您不能将
def
分配给值,因为def
不是值 - 它是对象中的方法。(x: T) => x * x
声明并实例化一个在运行时存在的函数对象。函数对象是扩展FunctionN
特征的匿名类的实例。FunctionN
特征带有一个apply
方法。名称apply
很特殊,因为它可以省略。表达式f(x)
被脱糖为f.apply(x)
。底线是 - 由于函数对象是存在于堆上的运行时值,因此您可以将它们分配给值、变量和参数,或者从方法中将它们作为返回值返回。
为了解决将方法分配给值的问题(这可能很有用),Scala 允许您使用占位符从方法创建函数对象。上面示例中的表达式
test1 _
实际上在方法test1
周围创建了一个包装函数 - 它相当于x =>;测试1(x)。
The
def
declares a method within a surrounding object/class/trait, similar to the way you define methods in Java. You can only usedef
s within other objects/classes/traits. In the REPL, you cannot see the surrounding object because it's "hidden", but it does exist.You cannot assign a
def
to a value, because thedef
is not a value - it's a method in the object.The
(x: T) => x * x
declares and instantiates a function object, which exists at runtime. Function objects are instances of anonymous classes which extendFunctionN
traits.FunctionN
traits come with anapply
method. The nameapply
is special, because it can be omitted. Expressionf(x)
is desugared intof.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 methodtest1
- it is equivalent tox => test1(x)
.def'ed 函数和 val'ed 函数之间没有区别:
看到了吗?所有这些都是函数,由
X => 表示。他们有 Y 类型。
您看到
X => 了吗? Y 类型?如果你这样做,请去看眼科医生,因为没有眼科医生。这里的类型是
(X)Y
,通常用来表示方法。实际上,
test1
、test2
、test3
和test4
都是方法,它们返回函数。test5
是一个返回java.lang.String
的方法。此外,test1
到test4
不带参数(无论如何,只有test1
可以),而test5
则带参数。所以,区别非常简单。在第一种情况下,您尝试将一个方法分配给一个 val,但没有填写该方法采用的参数。所以它失败了,直到你添加了一个尾部下划线,这意味着将我的方法变成一个函数。
在第二个示例中,您有一个函数,因此您不需要执行任何其他操作。
方法不是函数,反之亦然。函数是 FunctionN 类之一的对象。方法是与对象关联的某些代码段的句柄。
请参阅 Stack Overflow 上有关方法与函数的各种问题。
There's no difference between a def'ed function and a val'ed function:
See? All of these are functions, which is indicated by the
X => Y
type they have.Do you see an
X => Y
type? If you do, go see an ophthalmologist, because there's none. The type here is(X)Y
, commonly used to denote a method.Actually,
test1
,test2
,test3
andtest4
are all methods, which return functions.test5
is a method which returns ajava.lang.String
. Also,test1
throughtest4
do not take parameters (onlytest1
could, anyway), whiletest5
does.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.
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
FunctionN
classes. A method is a handle to some piece of code associated with an object.See various questions about methods vs functions on Stack Overflow.
下划线在不同的上下文中表示不同的含义。但它总是可以被认为是会出现在这里的东西,但不需要命名。
当应用代替参数时,效果是将方法提升为函数。
注意,该方法已经变成了类型为(String) => 的函数。细绳。
Scala 中方法和函数之间的区别在于方法类似于传统的 Java 方法。您不能将它们作为值传递。然而,函数本身就是值,可以用作输入参数和返回值。
提升还可以更进一步:
提升这个功能会产生另一个功能。这次的type() => (字符串)=> (字符串)
据我所知,这种语法相当于用下划线显式替换所有参数。例如:
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.
Note, the method has become a function of type (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.
The lifting can go further:
Lifting this function results in another function. This time of type () => (String) => (String)
From what I can tell, this syntax is equivalent to substituting all of the parameters with an underscore explicitly. For example: