函数式编程把函数当做一等公民,充分利用函数,支持函数的多种使用方式。 在 Scala 当中,函数是一等公民,像变量一样,既可以将函数作为函数的参数使用,也可以将函数赋值给一个变量。 Scala中函数的创建不用依赖于类或者对象
定义函数语法: val 函数名: 参数列表 => 函数返回值类型 = 函数体 // 不能指定形参 或 val 函数名 = 参数列表 => 函数体 // 可以指定形参 或 val 函数名 = new Function2[参数列表]{ def apply(参数列表):返回值类型=函数体 //返回值类型为参数列表中最后一个类型 } 或 (参数列表) => 函数体
注:声明中的参数列表可以只指定类型不指定参数名,在函数体中通过_表示参数名
示例:函数的定义
object ScalaDemo {
val f1 = (a: Int, b: Int) => a + b //没有指定返回值类型
val f2 = ((a: Int, b: Int) => a + b)
val f3 = (_: Int) + (_: Int)
val f4: (Int, Int) => Int = (_ + _) //指定返回值类型
val f5: (Int, Int) => Int = (x, y) => x + y
val f6: ((Int, Int) => Int) = {
(x, y) => x + y
}
val f7 = new Function2[Int, Int, Int] {
def apply(x: Int, y: Int): Int = if (x 42 // 无参函数
println(getTheAnswer())
}
定义方法
语法规则: def 方法名 ([参数名:参数类型], …)[[:返回值类型] =] { 语句… //完成某个功能 return 返回值 }
方法的返回值类型可以不写,编译器可以自动推断出来,但是对于递归函数,必须指定返回类型。
示例:
object ScalaDemo{
def add1(x:Int,y:Int):Int = x+y
//也可以定义成
def add2(x:Int,y:Int)=x+y
//也可以定义成
def add3(x:Int,y:Int){ //不指定返回值且没有行号,一定要用大括号将方法体括起来
x+y
}
}
示例:
object FunDemo {
def main(args: Array[String]): Unit = { //Unit:没有返回值
println(sum(1, 2, '-'))
}
//如果函数返回的类型是多种的,则推荐使用类型推导
def sum(n1: Int, n2: Int, op: Char) = {
if (op == '+') {
n1 + n2
} else if (op == '-') {
n1 - n2
} else {
null
}
}
}
方法和函数的区别
- 在 scala 中,方法和函数几乎可以等同,Scala中的方法就是函数,只是函数的使用方式更加的灵活多样。
- 方法与函数本质上一样,但是形式上略有差异。
- 方法和函数的定义的语法不同:用def 语句定义方法,val语句可以定义函数
- 方法一般定义在某个类、特质、或者object中
把方法作为参数传给一个方法或者函数的时候,方法自动被转换为函数。 将方法转换成函数的方式是:使用下划线_
示例:
object ScalaDemo {
def f1(n: Int): Int = { //方法
n * 2
}
def main(args: Array[String]): Unit = {
val f2 = f1 _ //将方法转换为函数
println(f2(10)) // 调用函数 20
}
}
递归函数
示例:请使用递归的方式,求出斐波那契数 1,1,2,3,5,8,13…第n项的值是多少?
object FunDemo {
def main(args: Array[String]): Unit = {
println(fbn(6))
}
def fbn(n: Int): Int = {
if (n == 1 || n == 2) {
1
} else {
fbn(n - 1) + fbn(n - 2)
}
}
}
示例:已知 f(1)=3; f(n) = 2*f(n-1)+1; 请使用递归的思想编程,求出 f(n)的值
object FunDemo {
def main(args: Array[String]): Unit = {
println(f(6))
}
def f(n: Int): Int = {
if (n == 1) {
3
} else {
2 * f(n - 1) + 1
}
}
}
5.6. 惰性函数 惰性计算(尽可能延迟表达式求值)是许多函数式编程语言的特性。Java 并没有为惰性提供原生支持,Scala 提供了。 当函数返回值被声明为 lazy 时,函数的执行将被推迟,直到我们首次对其取值,函数才会执行。这种函数我们称之为惰性函数。惰性在 Java 的某些框架代码中被称之为懒加载(延迟加载)。 注意: lazy 不能修饰 var 类型的变量 在调用函数时,加了lazy会导致函数的执行被推迟; 在声明一个变量时,如果给声明了 lazy,那么变量值得分配也会推迟。比如:lazy val i = 10。
示例: object FunDemo { def main(args: Array[String]): Unit = { lazy val res = sum(1,2) println(“res=” + res) //当需要使用到 res 时,就会真正的开始计算 } def sum(n1:Int,n2:Int): Int = { n1 + n2 } }
高阶函数高阶函数是指使用其他函数作为参数、或者返回一个函数作为结果的函数。
示例:函数作为方法的参数–模拟命令设计模式
object MethodAndFunctionDemo {
def m1(f: (Int, Int) => Int): Int = { //函数作为方法的参数
f(2, 6)
}
//定义一个求和函数f1,参数是两个Int类型,返回值是一个Int类型
val f1 = (x: Int, y: Int) => x + y
//再定义一个求积函数f2
val f2 = (m: Int, n: Int) => m * n
def main(args: Array[String]): Unit = { //main方法
//调用m1方法,并传入f1函数
val r1 = m1(f1)
println(r1)
//调用m1方法,并传入f2函数
val r2 = m1(f2)
println(r2)
}
}
示例:函数作为方法的返回值
object ScalaDemo {
def urlBuilder(ssl: Boolean, domainName: String): (String, String) => String = {
val schema = if (ssl) {
"https://"
} else {
"http://"
}
(endpoint: String, query: String) => s"$schema$domainName/$endpoint?$query"
}
def main(args: Array[String]): Unit = {
val domainName = "www.example.com"
def getURL = urlBuilder(ssl = true, domainName)
val endpoint = "users"
val query = "id=1"
val url = getURL(endpoint, query)
println(url)
}
}