1. 函数与方法区别
函数 | 方法 | |
---|---|---|
定义 | 为完成某一功能的程序语句的集合 一段子程序 | 类中的函数 |
定义位置 | 函数可以嵌套定义 | 类 |
重写与重载 | 无 | 可以 |
函数参数 | 可变参数 (数据类型后面加*) 默认值参数 带名参数 可变参数与默认值参数不可同时使用 参数列表中存在多个参数,那么可变参数一般放置在最后 将有默认值的参数放置在参数列表的后面 |
2. 基本语法
[修饰符] def 函数名 ( 参数列表 ) [:返回值类型] = {
函数体
}
private def test( s : String ) : Unit = {
println(s)
}
3. 函数至简原则
原则 | 说明 |
---|---|
省略return关键字 | 使用函数体的最后一行代码作为返回值 |
省略花括号 | 函数体逻辑代码只有一行情况下 |
省略返回值类型 | 返回值类型如果能够推断出来,那么可以省略 如果有 return,则不能省略返回值类型,必须指定 如果函数明确声明 unit,那么即使函数体中使用 return 关键字也不起作用 |
省略等号 | 一般返回值类型为unit时省略 如果有 return,则不能省略返回值类型,必须指定返回值类型 如果函数明确声明 unit,那么即使函数体中使用 return 关键字也不起作用 如果函数体返回值类型声明为Unit, 但是又想省略,那么此时就必须连同等号一起省略 |
省略参数列表 | 参数列表中没有声明任何的参数,那么参数列表可以省略 省略之后,调用时不能加 小括号 [即不能加参数列表] 如果函数无参,但是声明了参数列表,那么调用时,小括号,可加可不加 |
省略关键字def和函数名 | 省略关键字和函数名的同时也需要将 [ : 返回值类型 ] 同时省略,将等号增加一个箭头 即 (参数列表) => { 函数体 } 匿名函数不能独立使用 |
object TestHighFunc {
def main(args: Array[String]): Unit = {
// 至简原则细节
// (1)return 可以省略,Scala 会使用函数体的最后一行代码作为返回值
def func0( str :String ):String = {str + "\t----func0"}
// (2)如果函数体只有一行代码,可以省略花括号
def func1 (str : String) : String = str + "\t----func1"
// (3)返回值类型如果能够推断出来,那么可以省略(:和返回值类型一起省略)
def func2 (str : String) = str + "\t----func2"
// (4)如果有 return,则不能省略返回值类型,必须指定
// def func3 (str : String) = return str + "\t----func1"
def func3 (str : String) : String = return str + "\t----func3"
// (5)如果函数明确声明 unit,那么即使函数体中使用 return 关键字也不起作用
def func4 (str : String) : Unit = return str + "\t----func4"
// (6)Scala 如果期望是无返回值类型,可以省略等号 , 大括号不可省略(即使逻辑代码只有一行) : func6
// 将无返回值的函数称之为过程
def func5 (str : String) { println( str + "\t----func5")}
// def func6 (str : String) println( str + "\t----func6")
// (9)如果不关心名称,只关心逻辑处理,那么函数名(def)可以省略
var func7 = (a:Int , b : Int) => a * b
var func8 = (a:Int , b : Int) => b % a
println(func0("Hello Scala , High Function!!!"))
println(func1("Hello Scala , High Function!!!"))
println(func2("Hello Scala , High Function!!!"))
println(func3("Hello Scala , High Function!!!"))
println(func4("Hello Scala , High Function!!!"))
println(func5("Hello Scala , High Function!!!"))
println(func7(3 , 9))
println(func8(3 , 9))
}
}
注意
如果有 return,则不能省略返回值类型,必须指定
如果函数明确声明 unit,那么即使函数体中使用 return 关键字也不起作用
返回值为Unit时,省略等号的同时 , 大括号不可省略(即使逻辑代码只有一行)
无参函数定义时若省略参数列表,调用时无须写参数列表
4. 匿名函数
([形式参数[:参数类型],形式参数[:参数类型]...]) => {函数体}
注意
形式参数 数据类型可以省略,会根据形参进行自动的推导
形式参数只有一个,则圆括号可以省略
- 无形式参数和形式参数超过 1 的永远不能省略圆括号
匿名函数体只有一行,则大括号也可以省略
形式参数在函数体中只出现一次,则参数省略且后面参数可以用_代替
- 第一次出现的 _ 代表形式参数列表中的第 一 个形式参数
- 第n次出现的 _ 代表形式参数列表中的第n个形式参数
匿名函数体是一个函数,调用时只写该函数名即可
5. 高阶函数
高阶函数,其实就是将函数当成一个类型来使用,而不是当成特定的语法结构
5.1 函数可以作为值进行传递
如果将函数作为整体,而不是将执行结果赋值给变量,那么需要采用特殊符号:下划线
package ch04
object TestHighFunc2 {
def main(args: Array[String]): Unit = {
def func(name : String) : String = name
var a = func _
var b = func("6666")
println(a)
println(b)
}
}
ch04.TestHighFunc2$$$Lambda$1/2065951873@5e025e70
66666
使用下划线让函数作为对象使用,因为代码中没有明确变量的类型,所以需要通过取值类推断
如果变量声明的类型为函数类型,那么可以不适用下划线让函数作为对象
5.2 函数可以作为参数进行传递
将函数作为参数传入到函数中,记得传入参数时需去掉()即 传入函数类型的值 fun 或者 fun(因为知道传入的类型为函数类型,所以可以省略)
不去掉()的话会直接执行 会将执行结果作为参数传入
5.3 函数可以作为函数返回值返回
- 定义一个函数 func,它接收一个 Int 类型的参数,返回一个函数(记作 f1)。
- 它返回的函数 f1,接收一个 String 类型的参数,同样返回一个函数(记作 f2)。
- 函数 f2 接收一个 Char 类型的参数,返回一个 Boolean 的值。
- 要求调用函数 func(0) (“”) (‘0’)得到返回值为 false,其它情况均返回 true
package ch04
object TestHighFunc2 {
def main(args: Array[String]): Unit = {
def func(i :Int): String => (Char => Boolean) = {
def f1(s : String) : Char => Boolean = {
def f2(c : Char): Boolean ={
! (c == '0' && s == "" && i == 0)
}
f2 _
}
f1 _
}
println ( func(0)("")('0') )
println ( func(4)("")('0') )
println ( func(0)("_")('9') )
println ( func(4)("_")('9') )
}
}
false
true
true
true
- 上述程序第一步省略
package ch04
object TestHighFunc2 {
def main(args: Array[String]): Unit = {
def func2(i :Int): String => Char => Boolean = {
def f1(s : String) : Char => Boolean = {
c => ! (c == '0' && s == "" && i == 0)
}
f1
}
}
}
- 上述程序第二步省略
package ch04
object TestHighFunc2 {
def main(args: Array[String]): Unit = {
def func2(i :Int): String => Char => Boolean = {// 此处大括号亦可省略
s => c => ! (c == '0' && s == "" && i == 0)
}// 此处大括号亦可省略
}
}
6. 柯里化&闭包
函数柯里化:把一个参数列表的多个参数,变成多个参数列表
- 定义一个函数 func,它接收一个 Int 类型的参数,返回一个函数(记作 f1)。
- 它返回的函数 f1,接收一个 String 类型的参数,同样返回一个函数(记作 f2)。
- 函数 f2 接收一个 Char 类型的参数,返回一个 Boolean 的值。
- 要求调用函数 func(0) (“”) (‘0’)得到返回值为 false,其它情况均返回 true
package ch04
object TestHighFunc {
def main(args: Array[String]): Unit = {
def func(i :Int) (s : String) (c : Char): Boolean = ! (c == '0' && s == "" && i == 0)
}
}
- 上述程序进一步简写
package ch04
object TestHighFunc {
def main(args: Array[String]): Unit = {
def func(i :Int) (s : String) (c : Char) = ! (c == '0' && s == "" && i == 0)
}
}
如果一个函数,访问到了它的外部(局部)变量的值,那么这个函数和他所处的环境,称为闭包
7. 递归
尾递归 实现阶乘
package ch04
import scala.annotation.tailrec
object Factorial {
def main(args: Array[String]): Unit = {
// 尾递归
def fact(n :Int): Int ={
@tailrec
def loop( n :Int , res : Int):Int = {
if (n == 0) return res;
print(res + "\t")
loop( n - 1 , res * n)
}
loop(n , 1)
}
println(fact(5))
println("-------------------------------")
// 朴素递归 1
def factorial( n :Int ): Int ={
var a = n;
var res = a;
while( a != 1){
print(res + " ")
a -= 1;
res *= a ;
}
res;
}
println(factorial(5))
// 朴素递归 2
def factorial2( n :Int ): Int ={
if ( n == 0 ) return 1;
factorial2(n - 1) * n;
}
println(factorial2(5))
}
}
8. 控制抽象
值调用:把计算后的值传递过去
名调用:把代码传递过去
个人理解 : 将一段代码传入, 该代码的类型为 => [该代码块的最后一行类型]
package ch04
object DefineWhile {
def main(args: Array[String]): Unit = {
var n = 10;
while( n >= 1){
print(n + " ");
n -= 1;
}
println()
println("---------------------------------")
n = 10;
def DIYWhile(condition : => Boolean , op : => Unit) : Unit = {
if(condition) {
op
DIYWhile( condition, op)
}
}
DIYWhile( {n >= 1} , { print(n + " "); n -= 1;})
println()
println("---------------------------------")
n = 10;
def DIYWhile2(condition : => Boolean ) : (=> Unit) => Unit= {
def loop ( op : => Unit):Unit={
if(condition) {
op
DIYWhile2( condition )(op)
}
}
loop
}
DIYWhile2( {n >= 1} )({ print(n + " "); n -= 1;}) //第二项小括号可省略
}
}
10 9 8 7 6 5 4 3 2 1
---------------------------------
10 9 8 7 6 5 4 3 2 1
---------------------------------
10 9 8 7 6 5 4 3 2 1
- DIYWhile2第一次省略
package ch04
object DefineWhile {
def main(args: Array[String]): Unit = {
n = 10;
def DIYWhile2(condition : => Boolean ) : (=> Unit) => Unit= {
op => {
if(condition) {
op
DIYWhile2( condition )(op)
}
}
}
DIYWhile2( n >= 1 ){
print(n + " ");
n -= 1;
}
}
}
9. 惰性加载
当函数返回值被声明为 lazy 时,函数的执行将被推迟,直到我们首次对此取值,该函数才会执行
package ch04
object LazyLoad {
def main(args: Array[String]): Unit = {
lazy val c = sum ( 9 , 1)
println("第一次调用println")
println("第二次调用println: Result = " + c)
}
def sum ( a:Int , b :Int) = {
println("-----sum函数调用-----")
a + b
}
}
第一次调用println
-----sum函数调用-----
第二次调用println: Result = 10