函数基本语法
通过 def sum(x: Int, y: Int): Int = { x + y } 示例说明。 def 是定义函数的关键字 ; sum 为函数名; x 、 y 是参数名, Int 是参数类型;最后的 Int 是函数返回值类型;大括号内 x + y 是函数体。
函数和方法的区别
函数是完成某一功能的程序语句集合
类中的函数称为方法
Scala 语言语法结构灵活,可在任意语法结构中声明语法。
函数无重载和重写概念,方法可以重载和重写。代码中尝试对函数 test 进行重载定义会报错。
Scala 中函数可嵌套定义 ,如 def test2(): Unit ={} 可在其他函数内嵌套定义。
函数声明
不同类型函数定义
函数1: def test1(): Unit = { println("无参,无返回值") } ,无参数,返回类型为 Unit (表示无实际返回值 ),函数体执行打印操作。
函数2: def test2():String = { return "无参,有返回值" } ,无参数,返回类型为 String ,函数体返回特定字符串。
函数3: def test3(s:String):Unit = { println(s) } ,有一个 String 类型参数 s ,返回类型 Unit ,函数体打印传入参数。
函数4: def test4(s:String):String = { return s + "有参,有返回值" } ,有一个 String 类型参数 s ,返回类型 String ,返回拼接后的字符串。
函数5: def test5(name:String, age:Int):Unit = { println(s"$name, $age") } ,有多个参数( String 类型 name 和 Int 类型 age ) ,返回类型 Unit ,函数体按格式打印参数。
函数调用:在 main 函数中对上述定义的函数依次调用,如 test1() 、 println(test2()) 等,展示函数实际运行过程。
函数参数
可变参数:如 def test( s : String* ): Unit = { println(s) } ,参数 s 类型为 String* ,表示可变参数,可接收多个 String 类型参数,调用 test("Hello","Scala") 时, s 会作为 Array 类型处理。
参数位置规则:如果参数列表存在多个参数,可变参数一般放最后;有默认值的参数一般放置在参数列表后面 。
语法规则
返回值类型推断与省略:当返回值类型能被推断出时,可省略(连同 : 一起 )。比如函数逻辑简单,返回值类型明确时,可省略声明。
return 关键字与返回值类型:若函数体含 return ,不能省略返回值类型,必须明确指定,确保类型匹配。
函数声明为 unit 与 return :函数声明返回类型为 Unit (表示无实际返回值 )时,即便函数体有 return ,也不起作用。
无返回值函数的等号省略:期望无返回值(返回类型为 Unit )时,函数定义中等号可省略 ,这类函数也叫过程。
函数调用括号规则:无参但声明了参数列表的函数,调用时括号可加可不加;没参数列表的函数,定义和调用时括号都必须省略。
函数名省略:若不关注函数名,仅关心逻辑处理,定义函数时 def (函数名 )可省略 。
函数标准写法: def f(s : String) : String = { return s + " jinlian" } ,常规定义有参数、有返回值函数。
return 省略: def f1(s : String ) : String = { s + " jinlian" } ,省略 return ,Scala自动将函数体最后一行作为返回值。
花括号省略: def f2(s:String):String = s + " jinlian" ,函数体只有一行代码时,省略花括号。
返回值类型推断省略: def f3( s : String ) = s + " jinlian" ,返回值类型可推断,省略返回值类型声明。
含 return 时返回值类型必须指定: def f4() :String = { return "ximenqing4" } ,有 return ,明确指定返回值类型。
返回类型为 Unit 时 return 无效: def f5(): Unit = { return "dalang5" } ,虽有 return 但返回类型 Unit , return 不起作用。
无返回值函数等号省略: def f6() { } ,无返回值,省略等号 。
匿名函数
匿名函数是没有名字的函数,格式为 (x:Int) => {函数体} 。其中 x 是输入参数名, Int 是输入参数类型 , => 是分隔符,大括号内是具体代码逻辑。
参数类型省略原则:参数类型可省略,Scala会根据形参自动推导。比如在合适场景下, (x:Int) => {...} 可简化为 x => {...} 。
圆括号省略规则:类型省略后,若只有一个参数,圆括号可省略;无参数或参数超过1个时,圆括号不能省略 。如 x => {...} (单个参数可省略圆括号 ), (x:Int, y:Int) => {...} (多参数圆括号不能省 ) 。
大括号省略:当匿名函数只有一行代码时,大括号可以省略 。例如 x => x + 1 (等同于 x => { x + 1 } ) 。
参数省略与占位符:如果参数只出现一次,可省略参数名,后面用 _ 代替 。
高阶函数
模拟Map映射
定义 map 函数: def map(arr: Array[Int], op: Int => Int) = { for (elem <- arr) yield op(elem) } ,接收整数数组 arr 和一个将 Int 映射为 Int 的函数 op ,对数组每个元素应用 op 函数并返回新数组。
调用示例: val arr = map(Array(1, 2, 3, 4), (x: Int) => { x * x }) ,将数组元素平方。
模拟Filter过滤
定义 filter 函数: def filter(arr:Array[Int],op:Int =>Boolean) = { var arr1:ArrayBuffer[Int] = ArrayBuffer[Int]() for(elem <- arr if op(elem)){ arr1.append(elem) } arr1.toArray } ,接收整数数组 arr 和一个判断 Int 元素是否满足条件的函数 op ,筛选出满足条件元素组成新数组。
模拟Reduce聚合
定义 reduce 函数: def reduce(arr: Array[Int], op: (Int, Int) => Int) = { var init: Int = arr(0) for (elem <- 1 until arr.length) { init = op(init, elem) } init } ,接收整数数组 arr 和一个二元操作函数 op ,从数组第二个元素起,依次用 op 对元素聚合操作。
函数柯里化 & 闭包
闭包:函数访问其外部(局部)变量值,该函数及其所处环境构成闭包。
函数柯里化:将一个参数列表的多个参数变为多个参数列表。
递归
一个函数或方法在其函数体或方法体内再次调用自身,就是递归调用 。
控制抽象
值调用:把计算后的值传递过去 。如 def f = ()=>{ println("f...") 10 } 定义函数 f ,先打印字符串再返回10 ; def foo(a: Int):Unit = { println(a) println(a) } 接收 Int 类型参数并打印两次。 foo(f()) 调用时,先执行 f() 得到值10 ,再将10传给 foo 函数。
名调用:把代码传递过去 。同样定义 def f = ()=>{ println("f...") 10 } , def foo(a: =>Int):Unit = { println(a) } ,这里 a 是按名调用参数。 foo(f()) 调用时,不是先计算 f() 的值,而是将 f() 代码传递给 foo ,在 foo 中执行 f() 相关代码,实现先打印 f... 再打印10 。
注意:Java只有值调用,而Scala同时支持值调用和名调用
惰性加载
当函数返回值被声明为 lazy 时,函数执行会推迟,直到首次取值时才执行,这种函数叫惰性函数 。