package day04 import java.io.{File, PrintWriter} class Demo(desc: String) { override def toString: String = desc } object Demo { def main(args: Array[String]): Unit = { val d = new Demo("Scala 函数") println(d) test_1() test_2() test_3() test_4() test_5() // test_6() test_7() test_8() test_9() } // 类成员函数,和 Java 的成员方法一致,略 /** * 局部函数:在函数内部定义函数 * 在局部函数中可以访问外部定义的变量 * */ def test_1(): Unit = { val v_1 = "hello " def innerFun(): Unit = { println(v_1 + "inner function") } innerFun() } /** * 函数字面量(就是匿名函数) * 函数是 Scala 中的“头等公民”(W3C中这句话不知道什么意思。。。) * 匿名函数看起来不能指定返回值类型(语句最后一行执行的结果就是返回值) */ def test_2(): Unit = { // 函数字面量 var increase = (x: Int) => x + 1 println(increase(6)) // Lists 不可修改序列 val someNumbers = List(-11, -10, -5, 0, 5, 10) // 在 foreach 中使用匿名函数 someNumbers.foreach(i => println(i)) // 在 filter 中使用匿名函数 println(someNumbers.filter(i => i > 0)) } /** * 部分应用的函数(其实就是 python 中的偏函数) */ def test_3(): Unit = { // sum2 是 sum1 的简化写法 // Scala 允许使用“占位符”下划线”_”来替代一个或多个参数,只要这个参数值函数定义中只出现一次,Scala编译器可以推断出参数。 def sum1 = (a: Int, b: Int, c: Int) => a + b + c def sum2 = (_: Int) + (_: Int) + (_: Int) // 定义偏函数 val b = sum2(1, _: Int, 3) println(b(10)) } // 闭包 def test_4(): Unit = { var more = 1 // 定义:引用到函数外面定义的变量,定义这个函数的过程是将这个自由变量捕获而构成一个封闭的函数。 val addMore1 = (i: Int) => i + more println(addMore1(10)) // 当这个自由变量发生变化时,Scala 的闭包能够捕获到这个变化,因此 Scala 的闭包捕获的是变量本身而不是当时变量的值。 more = 100 println(addMore1(10)) // 如果变量在闭包在发生变化,也会反映到函数外面定义的闭包的值。 val addMore2 = (i: Int) => { more = more + i more } println(addMore2(1000)) println(addMore2(1000)) println(more) } // 函数–可变参数,命名参数,缺省参数 def test_5(): Unit = { // 可变参数 def echo(args: String*): Unit = { args.foreach(s => println(s)) } echo("1", "2", "3") val arr = Array("What's", "up", "doc?") echo(arr: _*) // 奇奇怪怪的语法 // 命名参数:使用命名参数允许你使用任意顺序传入参数 def speed(distance: Float, time: Float): Float = distance * time println(speed(10, 20)) println(speed(time = 10, distance = 20)) // 缺省参数值:Scala 在定义函数时,允许指定参数的缺省值,从而允许在调用函数时不指明该参数,此时该参数使用缺省值。缺省参数通常配合命名参数使用 def printTime(out: java.io.PrintStream = Console.out, divisor: Int = 1) = out.println("time = " + System.currentTimeMillis() / divisor) printTime() printTime(divisor = 666) } /** * 尾递归:在最后一行调用自身的递归 * 理论上来说,使用递归的性能不如使用循环 * 但是 scala 的编译器会针对尾递归进行优化(优化为循环) */ def test_6(): Unit = { def test(i: Int): Unit = { if (i > 100) { println("OVER") throw new Exception("boom!") // 用来显示调用栈 } else { test(i + 1) // 只要最后一行不是调用自身,就不构成尾递归 } // i + 1 } test(0) } // 减低代码重复 def test_7(): Unit = { // 函数可以作为参数传递(可以用来简化一些逻辑基本相似的代码) def check(s1: String, s2: String, checker: (String, String) => Boolean): Boolean = { // 该函数的类型为 (String,String ) =>Boolean,可以匹配任意使用两个 String 类型参数,返回值类型为 Boolean 的函数。 checker(s1, s2) } def test(s1: String, s2: String): Boolean = { false } println(check("aaa", "aaa", _.equals(_))) println(check("aaa", "aaa", test(_, _))) } // 柯里化函数(没什么卵用):柯里化是把接受多个参数的函数变换成接受一个单一参数的函数 def test_8(): Unit = { def test(i1: Int)(i2: Int)(i3: Int): Int = { i1 + i2 + i3 } println(test(1)(2)(3)) } // 创建新的控制结构:根据 scala 的高级函数特性,可以实现一些语法比较固定的控制结构 def test_9(): Unit = { // 自定义控制结构 def withPrintWriter(file: File, op: PrintWriter => Unit) { val writer = new PrintWriter(file) try { op(writer) } finally { writer.close() } } // 使用 withPrintWriter( new File("date.txt"), writer => writer.println(new java.util.Date) ) } // 传名参数 def test_10(): Unit = { var assertionsEnabled = true // 传值参数 def myAssert(predicate: () => Boolean) = if (assertionsEnabled && !predicate()) throw new AssertionError // 传名参数 def myNameAssert(predicate: => Boolean) = if (assertionsEnabled && !predicate) throw new AssertionError // 区别:传值参数是先计算后传值,传名参数相反 } }
来源:https://www.cnblogs.com/CSunShine/p/11972919.html