2017-04-23 57 views
2

我有一段非常简单的代码,我无法掌握。我正在阅读函数文字和方法。我正在做这个repl。scala函数字面值和方法和下划线

scala> val v = (a:Int, b:Int, c:Int) => {a+b+c} 
v: (Int, Int, Int) => Int = $$Lambda$1368/[email protected] 

scala> val v1 = v(1,2,_:Int) 
v1: Int => Int = $$Lambda$1369/[email protected] 

scala> v1 (10) 
res29: Int = 13 

scala> 

scala> val v2 = v _ 
v2:() => (Int, Int, Int) => Int = $$Lambda$1370/[email protected] 

scala> val v3 = v2() 
v3: (Int, Int, Int) => Int = $$Lambda$1368/[email protected] 

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/[email protected] 

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

我需要一些帮助来理解上述情况。我将从代码的底部开始。当我创建sumMe方法并在右侧用“_”将其分配给“v7”时,我知道我没有执行该方法。 val v7= sumMe_的输出对我来说很清楚,因为它简单地告诉我,v7将需要3个参数,并返回一个int。到目前为止感觉还行。

现在,当我进入我的`val v1 = v(1,2,_:Int)时,我仍然可以关联它将创建一个函数对象并赋值给v1,事实上我正在使用Scala s Function1's应用方法就是我所看到的。

我希望我理解它到目前为止。如果我上面的理解是正确的,那么造成最多混淆的是val v2 = v _。根据我所看到的输出结果,我必须以不同的方式调用这个东西。基本上我无法理解为什么V2与V7不同。 v2不需要任何参数,并给我一个我可以调用的函数。如果对于我定义为val v = ...的那种函数文字总是这样,那么当我做val v1 = v(1,2,:_Int)为什么我不能从类似于v2's case的scala v1:()=>Int=>Int中得到这个。

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

回答

2

在Scala中,我们区分方法功能。当你定义sumMe时,你正在定义一个方法,而你的其他声明是函数。方法,在斯卡拉,are non value types,这意味着该方法本身没有价值。当您尝试将其分配给某个值时,会出现一个名为eta expansion的隐式转换,将其转换为相应的函数类型。从规范:

方法类型不作为值的类型存在。如果使用方法名称 作为值,则其类型将隐式转换为相应的函数类型 。

既然我们配备了方法和功能的知识,让我们分析发生了什么。

当我创建的方法sumMe并指定为“第7版”与“_”就对了,我知道我不是执行方法

这是正确的。当您执行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]]

+0

嗨Yuval,你的解释有帮助。一旦我一遍又一遍地阅读你的帖子,我会回来再问你一些。你可以在此期间尝试多解释一下你的答案的结尾是什么意思 - 请注意后者是一个特殊的... 你是说我的代码中有一个编译错误? – curiousengineer

+0

@curiousengineer我删除了该部分,因为似乎存在与声明范围有关的问题。你可以在一个类的成员上做到这一点,但不是在一个方法声明中,我正在研究确切的规则,但他们对于答案并不重要。 –

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> 

每当你想传递一个“高清”将返回局部应用功能部分输入参数。例如:

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

fun3被称为部分应用函数。

1

有什么需要清除functionmethod

  1. 功能:我们使用valvar定义function,它往往是一个Anonymous Function,在斯卡拉,有Function0Function1,Function2 ...对于这些Anonymous Function,以及功能类型如:(T0, T1...TN) => U

    所以功能v实际上是一个Function3与参数。

  2. 方法:它用来def声明与method体与参数return type

对于val v2 = v _实际上等于val v2 =() => v,在那里通配符_将扩大到() => v,并v2意味着它是没有parameter.So val v3 = v2()创建另一个功能(v)功能是指invoke v2()创建v功能,所以基本上v3等于v

对于val v7 = sumMe _这意味着转换方法sumMe的功能,在那里通配符_将扩大到(a: Int, b: Int, c: Int) => sumMe(a, b, c),所以sumMe _将创建一个新的功能,这是基本等于v,如果使用v7 _也会产生相同的functionval v2 = v _

参考

Difference between method and function in Scala

相关问题