我开始学习一点Scala,我基本上都是 理解返回函数和currying的函数,但是 我已经看到了这样做的两种语法,我想要更好 了解差异,也许还有一些理论背后的原因 发生了什么事。
在第一种方法中(使用=>
)我可以通过指定来理解函数
要绑定到变量x
的参数。但是,当我尝试这样做
使用第二种方法,编译器告诉我需要指定_
第二个参数的外卡。
我明白我需要做什么,但我不知道为什么我需要做 这样的事情。有人可以告诉我Scala编译器是什么 在这做什么?
使用=>
def add(x:Int) = (y:Int) => x + (-y)
add: (x: Int)Int => Int
scala> def adder = add(100) // x is bound to 100 in the returned closure
adder: Int => Int
scala> adder(1)
res42: Int = 99
使用一个arg列表后跟另一个
的第二个方法scala> def add2(x:Int)(y:Int) : Int = x + y
add2: (x: Int)(y: Int)Int
scala> def adder2 = add2(100)
<console>:9: error: missing arguments for method add2;
follow this method with `_' if you want to treat it
as a partially applied function
def adder2 = add2(100)
^
scala> def adder2 = add2(100) _ // Okay, here is the '_'
adder2: Int => Int
scala> adder2(1) // Now i can call the curried function
res43: Int = 101
答案 0 :(得分:4)
您所看到的是方法类型和功能类型之间的区别。这是一个微妙的,有时令人困惑的差异。 This answer包含对方法类型和函数类型之间差异的非常全面的解释。这是您的问题的一些最相关的点:
函数类型(大致)是
(T1, ..., Tn) => U
形式的一种类型,它是标准库中特征FunctionN
的简写。方法类型是非值类型。这意味着没有值 - 没有对象,没有实例 - 使用方法类型......方法类型是
def
声明 - 除了def
之外的所有内容。
您无法直接指定方法执行val
:
def foo(x: Int) = x
val myFooVal = foo //does not compile
eta-expansion 的过程可以将方法转换为函数,您可以将其分配给val
:
val myFooVal = foo _
Here是一篇博客文章,深入探讨了eta扩展。
您的示例中有趣的是您将方法与函数混合。这完全没问题,但它可能是你在这里迷惑的一部分:
def add(x:Int) = (y:Int) => x + (-y)
这是返回函数的方法,而这个:
def add2(x:Int)(y:Int) = x + y
是一个纯方法,与所有方法一样,可以使用eta-expansion将其转换为函数类型:
add2 _ //Int => (Int => Int)
add2(2) _ //Int => Int
在REPL中玩游戏可能会有所启发,看看Scala如何区别对待这些类型:
def add(x:Int) = (y:Int) => x + (-y)
//add: (x: Int)Int => Int
def add2(x:Int)(y:Int) = x + y
//add2: (x: Int)(y: Int)Int
注意REPL的打印输出在这里有何不同。在第一个示例中,我们可以看到add
是一个返回Int => Int
类型的方法,这是一个函数。在第二个示例中,方法语法通过第二个参数保留。