scala函数文字和方法以及下划线

时间:2017-04-23 03:30:36

标签: scala functional-programming

我有一段非常简单的代码,我无法理解。我正在阅读函数文字和方法。我这是在repl。

scala> val v = (a:Int, b:Int, c:Int) => {a+b+c}
v: (Int, Int, Int) => Int = $$Lambda$1368/1731643198@4ae730ca

scala> val v1 = v(1,2,_:Int)
v1: Int => Int = $$Lambda$1369/903167315@93d6f4

scala> v1 (10)
res29: Int = 13

scala>

scala> val v2 = v _
v2: () => (Int, Int, Int) => Int = $$Lambda$1370/5485285@7dd5d17a

scala> val v3 = v2()
v3: (Int, Int, Int) => Int = $$Lambda$1368/1731643198@4ae730ca

scala> val v4 = v3(1,2,3)
v4: Int = 6

scala> def sumMe(a:Int, b:Int, c:Int) = { a+b+c}
sumMe: (a: Int, b: Int, c: Int)Int

scala> val v7 = sumMe _
v7: (Int, Int, Int) => Int = $$Lambda$1371/906350712@6c86938f

scala> v7(1,2,3)
res30: Int = 6

我需要一些帮助来理解上面发生的事情。我将从代码的底部开始。当我创建方法sumMe并将其分配给右边带有“_”的“v7”时,我知道我没有执行该方法。 val v7= sumMe_的输出对我来说非常清楚,因为它只是告诉我v7将需要3个参数,并返回一个int。到目前为止感觉还可以。

现在,当我转到我的`val v1 = v(1,2,_:Int)时,我仍然可以关联它将创建一个函数对象并分配给v1,实际上我正在使用Scala 我将其视为Function1的apply方法。

我希望到目前为止我能理解它。如果我上面的理解是正确的,最引起混淆的是val v2 = v _。根据我看到的输出,我必须以不同的方式称呼这个东西。基本上我无法理解为什么v2与v7不同。 v2没有参数,并给了我一个我可以调用的函数。如果对于我定义为val v = ...的那种函数文字总是如此,那么当我val v1 = v(1,2,:_Int)时,为什么我不能从scala v1:()=>Int=>Int得到这个类似于v2's case

最后,为什么v7=sumMe _不会给我与val v2 = v_相同的输出

3 个答案:

答案 0 :(得分:3)

在Scala中,我们将方法函数区分开来。定义sumMe时,您将定义一个方法,而其他声明则是函数。 Scala中的方法are non value types,意味着方法本身没有价值。当您尝试将其分配给值时,会有一个名为eta expansion的隐式转换,用于将其转换为相应的函数类型。从规范:

  

方法类型不作为值的类型存在。如果使用方法名称   作为一个值,它的类型被隐式转换为一个对应的   功能类型。

现在我们已经掌握了方法和功能的知识,让我们分析一下发生了什么。

  

当我创建方法sumMe并将其分配给右边带有“_”的“v7”时,我知道我没有执行方法

没错。执行sumMe _时,您正在使用eta-expansion将方法转换为函数。

  

现在,当我去val v1 = v(1, 2, _: Int)时,我仍然可以将其关联起来   它将创建一个函数对象并分配给v1

再一次,你是对的。 v1现在是Function1[Int, Int]类型的部分应用函数。

  

基本上我无法理解为什么v2与v7不同。

什么是v2?它是通过部分应用现有函数对象创建的函数对象。由于类型Function3[Int, Int, Int, Int]的此函数已在其参数列表中修复,因此部分应用它只会将其嵌套在另一个函数对象中,现在类型为Function0,使其成为Function0[Function3[Int, Int, Int, Int]]

答案 1 :(得分:2)

在Scala中,函数是值,表示您可以在变量中分配任何函数。无论何时在def前面应用占位符(“_”),它都会将def转换为具有相同输入和输出类型的函数。如果在值前面应用占位符,它将转换为将单位作为输入并返回值作为输出的函数** [()=> T] **。例如:

 scala> val a = 2
 a: Int = 2

scala> val fun1  = a _
fun1: () => Int = <function0>

scala> def sum(a:Int, b:Int) = a+ b
sum: (a: Int, b: Int)Int

scala> val fun2 = sum _
fun2: (Int, Int) => Int = <function2>

每当您尝试在“def”中传递部分输入参数时,它将返回部分应用功能。例如:

scala> val fun3 = sum(1,_:Int)
fun3: Int => Int = <function1>

fun3被称为部分应用函数。

答案 2 :(得分:1)

functionmethod

需要清除
  1. 功能:我们使用valvar来定义function,它通常是Anonymous Function ,在 Scala 中,这些Function0Function1Function2Anonymous Function ...,函数类型如下:{{1 }}

      

    所以功能 (T0, T1...TN) => U实际上是v 3 参数。

  2. 方法:已经习惯Function3def身体申报参数和{{1 }}

  3. method实际上等于return type,其中通配符val v2 = v _将扩展为val v2 = () => v,而_表示它是创建的功能另一个没有参数的函数(() => v)。所以v2表示v创建val v3 = v2()函数,所以基本上invoke v2()等于v

    对于v3,这意味着将方法 v转换为函数,其中通配符val v7 = sumMe _将扩展为sumMe,因此{{1将创建一个基本上等于_的新函数,如果您使用(a: Int, b: Int, c: Int) => sumMe(a, b, c),它也会创建与sumMe _相同的v

    <强>参考

    Difference between method and function in Scala