参考文章:
1.深入理解Scala中的函数式编程
https://blog.csdn.net/a2011480169/article/details/53151279
2.scala的函数式编程(一)
https://blog.csdn.net/lazy_moon/article/details/81771402
3.Scala函数式编程笔记
https://blog.csdn.net/weixin_41074929/article/details/81870145
Scala 提供函数式变量 ,Java 是不具备的函数式变量的特性。Scala 的这种个特性,更像C++/C 中的函数指针,并可以非常方便的实现闭包特性。下面让我们学习一下Scala 中的函数编程。
Scala 中函数式编程主要分为以下几个方面:
1.Scala中函数的地位
2.Scala中函数式编程基本知识
2.1 Java 中的lambda表达式
3.Scala函数字面量
3.1 Scala 函数变量基本写法
3.2 Scala 函数变量简写方式
4.Scala高阶函数
4.1 接受 匿名函数 / 函数变量 的函数
4.2 返回 函数变量 的函数
5.scala 中闭包的实现
6.Scala部分应用函数
7.Scala柯里化函数
1.Scala中函数的地位
①在Scala当中,函数是一等公民,像变量一样,既可以作为函数的参数使用,也可以将函数赋值给一个变量。
②在Scala当中,函数是一等公民,函数的创建不用依赖于类、特质或者对象,而在Java当中,函数的创建则要依赖于类、抽象类或者接口。
2.Scala中函数式编程基本知识
scala 中的函数式 编程的写法非常类似于 java8 中的 lambda 表达式 (函数编程) 。建议有Java基础,但是没有了解过 scala 的同学先看下 Java8 中的 lambda 表达式。
2.1 Java 中的lambda表达式
这里是我收藏的一篇 Java8 lambda 表达式的语法。
Java_ Java8 的 lambda 表达式
https://blog.csdn.net/u010003835/article/details/76833247
3.Scala函数字面量
3.1 Scala 函数变量基本写法
scala 中的变量不仅仅可以是 基础类型 / 自定义类的实例, 也可以是函数表达式。
下面将展示如何将一个 函数表达式 (匿名函数) 赋值给一个 scala 的变量。
函数字面量 / 匿名函数 主要是定义一个函数表达式, 并将表达式赋值给一个变量。
方式一 :隐式定义
val f = (i :Int) => { i % 2==0 }
f(3)
讲解:
1. =>
=> 表示转换器,表达式转变了符号左边 (名为 i 的 Int 变量) 的参数列表,应用符号 (在这个例子中,表达式返回 Boolean值) 右边的算法生成新的结果。
2. (i: Int)
1)表示函数接受 1个参数
2)该参数为 Int 类型
3. 其他
该函数的返回值类型,为最后一行的表达式的变量类型。
特点:
优点 :
1. 函数字面量 / 匿名函数 定义简单,代码量小
缺点 :
1. 函数字面量 / 匿名函数 定义不够明了, 不能一眼看出返回值类型
适用场景:
函数字面量 表达式 较为简单的场景,函数的返回值需要一眼能看出来.
方式二 :显式定义
val j: (Int) => Boolean = (a) => {
a % 2 == 0
}
讲解:
1. val j: (Int) => Boolean
定义了一个变量j , 该变量为 匿名函数类型。 该函数接受一个参数,并返回一个 Boolean 类型的变量。
2.
(a) => {
a % 2 == 0
}
等号右边的代码,就是函数变量的方法定义。
特点:
优点 :
1. 函数字面量 / 匿名函数 能一眼看出返回值,需要更多的代码编写,并确定好返回值类型。
缺点 :
1. 函数字面量 / 匿名函数 定义较为复杂
适用场景:
函数字面量 表达式 代码逻辑较为复杂的场景, 需要良好的编码格式规范等
3.2 Scala 函数变量简写方式
对于上面的代码来说,我们可以编写出更简洁的代码,常见的简写形式有以下几种。
1. 当函数体较为简单,只有一行代码的情况下。
此时,我们可以省略 { } 括号,如下定义:
val d = (i: Int) => i % 2 == 0
2.函数只有一行代码,且参数仅被调用一次的情况。
val g: (Int, Int) => Int = _ + _
该函数有2个参数,返回值为 Int 类型,第一个 _ 表示第一个参数 , 第二个参数表示第二个参数
4.Scala高阶函数
Scala 中的高阶函数,主要是指
1.Scala 中的函数 可以接受 函数作为参数。
2.Scala 中的函数可以返回函数作为参数。
下面分别讨论这两种情况
4.1 接受 匿名函数 / 函数变量 的函数
object funcVar2 {
def operaTwoAndReturnInt(a: (Int, Int) => Int, b: Int, c: Int): Int = {
a(b, c)
}
def main(args: Array[String]): Unit = {
val returnVal = funcVar2.operaTwoAndReturnInt((a, b) => {
a + b
}, 2, 3)
println(returnVal)
}
}
输出:
5
例如:
def operaTwoAndReturnInt(a: (Int, Int) => Int, b: Int, c: Int): Int = {
a(b, c)
}
解析:
operaTwoAndReturnInt 接受一个函数参数。
函数参数为如下形式:
a: (Int, Int) => Int : 也就是上面显示定义函数变量的形式。不懂的请参考前面的文档
函数功能:
传入一个函数变量,并传入两个参数 b,c 并调用该函数。
4.2 返回 函数变量 的函数
这个与上面的传入函数参数的比较相像。其实就是上面各种使用方法的结合。
示例如下:
package funcVar
/**
* Created by szh on 2018/12/28.
*/
object funcVar3 {
def getFunc(name: String): (Int, Int) => Int = {
var returnFunc: (Int, Int) => Int = null
if (name == "add") {
returnFunc = (a, b) => {
a + b
}
} else if (name == "sub") {
returnFunc = (a, b) => {
a - b
}
}
//返回值
if (null == returnFunc) {
(a: Int, b: Int) => {
a * b
}
} else {
returnFunc
}
}
def main(args: Array[String]): Unit = {
val add = getFunc("add")
println(add(2, 3))
val sub = getFunc("sub")
println(sub(4, 3))
val mult = getFunc("other")
println(mult(3, 4))
}
}
我们定义了这么一个函数:
def getFunc(name: String): (Int, Int) => Int = {
var returnFunc: (Int, Int) => Int = null
if (name == "add") {
returnFunc = (a, b) => {
a + b
}
} else if (name == "sub") {
returnFunc = (a, b) => {
a - b
}
}
//返回值
if (null == returnFunc) {
(a: Int, b: Int) => {
a * b
}
} else {
returnFunc
}
}
该函数接收一个String, 根据String的值,返回各种类型的函数。
当为 “add” 时:
返回相加的函数
当为 "sub" 时:
返回相减的函数
当为 其他值 时:
返回相乘的函数
5.Scala中的闭包
闭包的含义:
闭包(语法闭包或者函数闭包)是一个函数联通该函数的非局部变量的引用环境。闭包允许函数访问其直接语法作用域之外的变量。
其他定义:
闭包是满足下面三个条件的一段代码块,
1.代码块可以当作值来传递
2.同时可以被任何拥有该值的对象按需执行
3.可以引用上下文中已经创建的变量(如它的封闭是相对于变量访问,在数学上称之为“关闭”)
下面给出2个简单的例子:
例子一
object funVar4 {
def main(args: Array[String]): Unit = {
var standardAge = 20
val q = (age:Int)=> age >= standardAge
println(q(23))
standardAge = 30
println(q(20))
}
}
true
false
尽管自由变量超出了函数的有效作用域,但当自由变量发生变化时,函数还是能够捕捉到这个变化。
例子二:
package funcVar {
class Foo {
def exec(f: (String) => Unit, name: String): Unit = {
f(name)
}
}
}
/**
* Created by szh on 2019/1/3.
*/
object funVar5 {
def main(args: Array[String]): Unit = {
var hello = "Hello"
val sayHello: (String) => Unit = (name) => println(s"$hello ,$name")
val foo = new funcVar.Foo
foo.exec(sayHello, "Al")
hello = "Hola"
foo.exec(sayHello, "Leona")
}
}
6.Scala部分应用函数
①部分应用函数只是在“已有函数”的基础上,提供部分默认参数,未提供默认参数的地方使用下划线替代,从而创建出一个“函数值”,在使用这个函数值(部分应用函数)的时候,只需提供下划线部分对应的参数即可.
②部分应用函数本质上是一种值类型的表达式,在使用的时候不需要提供所有的参数,只需要提供部分参数.
部分应用函数示例:
package funcVar
/**
* Created by szh on 2019/1/3.
*/
object funVar6 {
def main(args: Array[String]): Unit = {
val sum = (a: Int, b: Int, c: Int) => a + b + c
val f: Int => Int = sum(10, 10, _: Int)
val g: (Int, Int) => Int = sum(_: Int, 20, _: Int)
println(f(20))
println(g(10, 20))
}
}
7.Scala柯里化函数
①scala中的柯里化指的是将原来接受两个参数的函数变成新的接受一个参数的函数的过程.新的函数返回一个以原有第二个参数作为参数的函数.
package funcVar
/**
* Created by szh on 2019/1/3.
*/
object funcVar7 {
def main(args: Array[String]): Unit = {
def sum(x: Int)(y: Int) = println(x + y)
def multiply(x: Int)(y: Int) = println(x * y)
sum(10)(20)
multiply(10)(20)
}
}
应用场景:
本人表示没有使用过 柯里化函数 ,不知道该函数有什么作用。先Mark 一下,知道后补上。