44

这是一个小的 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 _基本上意味着一个带有参数的函数,它被赋予“。但是为什么这与 justtest1完全相同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>

在这里它没有_defed 函数和ed 函数有什么区别val

4

3 回答 3

58

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

您不能将 a 分配def给一个值,因为def它不是一个值 - 它是对象中的一个方法。

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

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

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

于 2011-02-15T21:13:18.117 回答
53

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>

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

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

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

实际上,、test1和都是返回函数的方法。是一个返回 a 的方法。另外,通过不带参数(无论如何只能),而可以。test2test3test4test5java.lang.Stringtest1test4test1test5

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

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

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

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

于 2011-02-16T01:03:58.760 回答
11

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

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

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

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

注意,方法已经变成了(String) => String 类型的函数。

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

提升可以走得更远:

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

提升此功能会导致另一个功能。这次的类型 () => (String) => (String)

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

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>
于 2011-02-15T23:00:48.547 回答