20 柯理化
柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术。
是把接受多个参数的函数变成接受一个参数的函数;
柯理化的两种表现形式:
以 加法函数为例:
def curring(x:Int)(y:Int) = x + y
def curring(x:Int) = (y:Int) => x + y
在柯理化形式的基础上,固定一个参数,传入一个参数
scala> def curring(x:Int)(y:Int) = x + y
curring: (x: Int)(y: Int)Int
scala> curring(4)(5)
res23: Int = 9
// 第一种方式
scala> val func1 = curring(5)_
func1: Int => Int = <function1>
scala> func1(4)
res25: Int = 9
// 第二种方式
scala> val func2 = (x:Int) => curring(x)(5)
func2: Int => Int = <function1>
scala> func2(4)
res26: Int = 9
scala> def curring(x:Int) = (y:Int) => x + y
curring: (x: Int)Int => Int
// 第三种方式
scala> val func3 = (x:Int) => curring(x)(5)
func3: Int => Int = <function1>
scala> func3(4)
res27: Int = 9
柯里化函数,配合implicit关键字使用
// 定义带有隐式参数的add方法
// implicit 修饰参数,代表该参数是隐式参数
scala> def add(a:Int)(implicit b:Int = 5) = a + b
add: (a: Int)(implicit b: Int)Int
// 直接传参
scala> add(4)(5)
res22: Int = 9
scala> add(4)(10)
res24: Int = 14
// 执行时,首先找当前环境是否有和隐式参数类型相同的隐式值,如果找到,用隐式值作为隐式参数
// 如果没找到,看隐式参数是否有默认值,如果有,使用默认值
// 如果还没找到,那就抛异常
// 当前环境没有和隐式参数类型相同的隐式值,隐式参数有默认值,使用默认值
// 4 + 5(默认值)
scala> add(4)
res25: Int = 9
// 定义隐式值
scala> implicit val b1:Int = 20
b1: Int = 20
// 当前环境有和隐式参数类型相同的隐式值,使用隐式值
// 4 + 20(隐式值)
scala> add(4)
res26: Int = 24
// 通过 implicitly[Int] 可提取出当前环境的隐式值并赋给变量
scala> val c:Int = implicitly[Int]
c: Int = 20
// 定义String类型隐式值
scala> implicit val b2:String = "aa"
b2: String = aa
scala> add(4)
res27: Int = 24
// 定义 Int类型隐式值, 当前环境有两个Int类型的隐式值
scala> implicit val b3:Int = 30
b3: Int = 30
// 由于当前环境有两个Int类型的隐式值,调用时不知道找哪个,所以报错
scala> add(4)
<console>:16: error: ambiguous implicit values:
both value b1 of type => Int
and value b3 of type => Int
match expected type Int
add(4)
^
// 由于当前环境已乱套,可通过退出重进解决
scala> :quit
C:\Users\My>scala
Welcome to Scala 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_131).
Type in expressions for evaluation. Or try :help.
scala>
在开发环境中使用柯里化和implicit,切记不能在同一个类中使用
package util
// 隐式成员是单独放在一个地方,使用的时候引入
object MyPredef {
// 定义隐式值1
implicit val b1:Int = 10
// 定义隐式值2
implicit val b2:Int = 20
}
package day03
object CurringDemo {
// 定义带有隐式参数的方法
def add(a:Int)(implicit b:Int = 5) = a + b
def main(args: Array[String]): Unit = {
println(add(4)(1))
println(add(4))
// 引入隐式值之后,当前环境就有隐式值了
import util.MyPredef.b1
println(add(4))
// 当前环境有两个Int类型隐式值,报异常
// import util.MyPredef.b2
// println(add(4))
}
}