掌握Scala函数

一、声明函数

  • 函数其实是一段具有特定功能的代码的集合,由函数修饰符、函数名、函数参数列表、函数返回值声明与函数体组成。

(一)显式声明函数

1、声明格式

[public | private | protected] def 函数名(参数列表) : 返回值声明 = {函数体}

2、注意事项

  • 函数通过def关键字定义
  • def前面可以具有修饰符,可以通过privateprotected来控制其访问权限。注意默认访问权限是public
  • 还可使用overridefinal等关键字修饰
  • 函数体中return关键字往往可以省略掉,一旦省略掉,函数将会返回整个函数体中最后一行表达式的值,这也要求整个函数体的最后一行必须是正确类型的值的表达式
  • scala一般都可以自动推断出返回值类型,所以通常返回值类型声明可以省略,但是注意,如果因为省略了返回值类型造成歧义,则一定要写上返回值声明
  • 如果函数体只有一行内容,则包裹函数体的大括号可以省略
  • 如果返回值类型是Unit,则另一种写法是可以去掉返回值类型和等号,把方法体写在花括号内,而这时方法内无论返回什么,返回值都是Unit

3、案例演示

(1)加法函数

  • 创建net.cl.day08包,在包里创建Example01对象
    package net.cl.day08
    
    import scala.io.StdIn
    
    /**
     * 功能:显式声明函数
     * 作者:cl
     * 日期:2023年03月30日
     */
    object Example01 {
      def add1(a: Int, b: Int): Int = {
        return a + b
      }
    
      def add2(a: Int, b: Int): Int = {
        a + b
      }
    
      def add3(a: Int, b: Int) = {
        a + b
      }
    
      def add4(a: Int, b: Int) = a + b
    
      def add5(a: Int, b: Int) {
        println(a + " + " + b + " = " + (a + b))
      }
    
      def main(args: Array[String]): Unit = {
        print("a = ")
        val a = StdIn.readLine().toInt
        print("b = ")
        val b = StdIn.readLine().toInt
    
        println(a + " + " + b + " = " + add1(a, b))
        println(a + " + " + b + " = " + add2(a, b))
        println(a + " + " + b + " = " + add3(a, b))
        println(a + " + " + b + " = " + add4(a, b))
        add5(a, b)
      }
    }
    

(2)阶乘函数

  • 显式声明阶乘函数并调用,在net.cl.day08包里创建Example02对象
    package net.cl.day08
    
    import scala.io.StdIn
    
    /**
     * 功能:显式声明阶乘函数并调用
     * 作者:cl
     * 日期:2023年03月30日
     */
    object Example02 {
      def factorial(n: Int): Long = {
        var jc = 1
        (1 to n).foreach(i => jc = jc * i)
        jc
      }
    
      def main(args: Array[String]): Unit = {
        print("n = ")
        val n = StdIn.readInt()
        println(n.toString + "! = " + factorial(n))
      }
    }
    

(二)隐式声明函数

1、声明格式

(参数列表) => {函数体}

2、注意事项

  • 如果函数体只有一行,那么大括号可以省略
  • 如果参数类型可以推测得知,那么参数列表中类型声明可以省略
  • 如果函数参数列表中只有一个参数,在不会产生歧义的情况下,小括号可以省略

3、案例演示

(1)加法函数

  • net.cl.day08包里创建Example03对象
    package net.cl.day08
    
    import scala.io.StdIn
    
    /**
     * 功能:隐式声明函数
     * 作者:cl
     * 日期:2023年03月30日
     */
    object Example03 {
      val add1 = (a: Int, b: Int) => {a + b}
      val add2 = (a: Int, b: Int) => a + b
      val add3 = (n: Int) => n + 1
    
      def main(args: Array[String]): Unit = {
        print("a = ")
        val a = StdIn.readInt()
        print("b = ")
        val b = StdIn.readInt()
    
        println(a + " + " + b + " = " + add1(a, b))
        println(a + " + " + b + " = " + add2(a, b))
        println(a + " + " + 1 + " = " + add3(a))
      }
    }
    

 

(2)打印直角三角形

  • 方法一、采用传统的双重循环实现
  • 方法二、采用单重循环配上流间变量来实现
  • 方法三、采用映射算子(map())和遍历算子(foreach())来实现

 

 

(3)计算1 + 2 + 3 + …… + 100的值

  • 不采用循环,而采用归约算子(reduce())算子来完成,归约算子传入一个匿名函数_ + _(x, y) => x + y

 

二、Scala函数种类

(一)成员方法

1、基本概念

  • 函数被使用在类的内部,作为类的一个成员,称为类的成员方法。

2、案例演示

任务:显示文件中长度超过15的行

  • 在项目根目录里创建文本文件text.txt

 

 在net.cl.day08包里创建Example04对象

package net.cl.day08

import scala.io.Source

/**
 * 功能:显示文件中长度超过15的行
 * 作者:cl
 * 日期:2023年03月30日
 */
object Example04 {
  def filter(line: String, len: Int): Boolean = {
    line.length > len
  }

  def getLinesFromFile(path: String, len: Int) = {
    val lines = Source.fromFile(path).getLines()
    for (line <- lines if filter(line, len)) yield line
  }

  def main(args: Array[String]): Unit = {
    val lines = getLinesFromFile("text.txt", 15)
    for (line <- lines) println(line + " " + line.length)
  }
}

(二)局部函数

1、基本概念

  • 函数内嵌的函数称为局部函数,这样的函数,只能在外部函数内部使用,外界无法访问。注意,Java是不允许函数嵌套的,但是Scala是允许的

2、案例演示

任务:采用局部函数显示文件中长度超过15的行

  • net.cl.day08包里创建Example05对象
    package net.cl.day08
    
    import scala.io.Source
    
    /**
     * 功能:采用局部函数显示文件中长度超过15的行
     * 作者:cl
     * 日期:2023年03月30日
     */
    object Example05 {
      def getLinesFromFile(path: String, len: Int) = {
        def filter(line: String, len: Int): Boolean = {
          line.length > len
        }
    
        val lines = Source.fromFile(path).getLines()
        for (line <- lines if filter(line, len)) yield line
      }
    
      def main(args: Array[String]): Unit = {
        val lines = getLinesFromFile("text.txt", 15)
        for (line <- lines) println(line + " " + line.length)
      }
    }
    

(三)匿名函数

1、基本概念

  • 函数在Scala中是头等公民,这体现在函数可以任意赋值给变量或常量,甚至可当作方法的实参或当作方法的返回值。在Java中只有变量或常量才能这么去使用。将函数直接量赋值给一个常量或变量,得到就是一个函数值,在需要时可以通过这个函数值来调用方法本身。

2、案例演示

任务:将函数赋值给常量

  • net.cl.day08包里创建Example06对象
    package net.cl.day08
    
    /**
     * 功能:将函数赋值给常量
     * 作者:cl
     * 日期:2023年03月30日
     */
    object Example06 {
      def sum(a: Int, b: Int): Int = a + b
    
      def main(args: Array[String]): Unit = {
        // 直接调用显式函数
        val r = sum(100, 150)
        println("r = " + r)
    
        // 将函数赋值给常量
        val sum1 = sum(_, _)
        val r1 = sum1(100, 150)
        println("r1 = " + r1)
    
        // 将函数固定一个参数后赋值给常量
        val sum2 = sum(_: Int, 100)
        val r2 = sum2(150)
        println("r2 = " + r2)
    
        // 将隐式函数赋值给常量
        val sum3 = (a: Int, b: Int) => a + b
        val r3 = sum3(100, 150)
        println("r3 = " + r3)
      }
    }
    

(四)高阶函数

1、基本概念

  • 函数可以作为另一个函数的参数被传递或作为另一个函数的返回值。

2、案例演示

任务1、演示函数作为函数的参数

  • net.cl.day08包里创建Example07对象
    package net.cl.day08
    
    /**
     * 功能:演示函数作为函数的参数
     * 作者:cl
     * 日期:2023年03月30日
     */
    object Example07 {
      def printStr: (String) => Unit = {
        x => println(x)
      }
    
      def main(args: Array[String]): Unit = {
        val cities = List("北京", "上海", "深圳", "泸州")
        cities.foreach(printStr)
      }
    }
    

 

任务2、演示函数作为函数的返回值

  • net.cl.day08包里创建Example08对象
    package net.cl.day08
    
    import scala.io.StdIn
    
    /**
     * 功能:演示函数作为函数的返回值
     * 作者:cl
     * 日期:2023年03月30日
     */
    object Example08 {
      def findRecipe(name: String): (String) => (String) = {
        if (name == "鸡肉") {
          (food: String) => {
            println("把" + food + "切丁,放在锅里烧,出锅")
            "美味的宫保鸡丁"
          }
        } else if (name == "鸭子") {
          (food: String) => {
            println("把" + food + "洗干净,放在火上好,烤熟")
            "美味的北京烤鸭"
          }
        } else {
          (food: String) => {
            println("把" + food + "洗净,放在锅里烧,烧熟")
            "美味的食物"
          }
        }
      }
    
      def cook(food: String): String = {
        val recipe = findRecipe(food)
        recipe(food);
      }
    
      def main(args: Array[String]): Unit = {
        print("食材:")
        val food = StdIn.readLine()
        println(cook(food))
      }
    }
    

三、神奇占位符

(一)基本概念

Scala中的下划线_是一个神奇的占位符,可以用它当作一个或多个参数来使用。可以使用下划线_占位符的前提要求是每个参数在函数直接量中仅出现一次,满足条件的情况下,可以去掉参数的说明,直接在函数体中使用下划线即可。使用下划线时,如果类型可以自动推断出,则不用声明类型,如果无法自动推断类型,则在下划线后自己来显式声明类型即可
 

(二)案例演示

任务1、演示过滤集合

  • net.cl.day08包里创建Example09对象
    package net.cl.day08
    
    /**
     * 功能:过滤集合
     * 作者:cl
     * 日期:2023年03月30日
     */
    object Example09 {
      def main(args: Array[String]): Unit = {
        val list = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
        println(list)
    
        println("奇数子列表:" + list.filter((num: Int) => {
          num % 2 == 1
        }))
    
        println("偶数子列表:" + list.filter(_ % 2 == 0))
      }
    }
    

任务2、演示处理集合

  • net.cl.day08包里创建Example10对象
    package net.cl.day08
    
    /**
     * 功能:处理集合
     * 作者:cl
     * 日期:2023年03月30日
     */
    object Example10 {
      def main(args: Array[String]): Unit = {
        val list = List(1, 2, 3, 4, 5, 6, 7)
    
        println(list)
    
        list.foreach((x: Int) => {
          print((x * 10) + "\t")
        })
        println()
    
        println(list.map((x: Int) => {
          x * 10
        }))
    
        println(list.map(_ * 10))
      }
    }
    

任务3、演示参数占位符

  • net.cl.day08包里创建Example11对象
    package net.cl.day08
    
    /**
     * 功能:参数占位符
     * 作者:cl
     * 日期:2023年03月30日
     */
    object Example11 {
      def main(args: Array[String]): Unit = {
        def sum(a: Int, b: Int, c: Int): Int = a + b + c
    
        // 直接调用原函数
        println("sum = " + sum(3, 4, 5))
    
        // 全部参数使用占位符
        val sum1 = sum(_, _, _)
        println("sum1 = " + sum1(3, 4, 5))
        var sum2 = sum _
        println("sum2 = " + sum2(3, 4, 5))
    
        // 部分参数使用占位符
        val sum3 = sum(_, 4, _)
        println("sum3 = " + sum3(3, 5))
      }
    }
    

四、闭包

(一)基本概念

如果在函数定义时,如果用到了上下文中的变量,则函数的具体执行将会和该变量的值具有了相关性,即这个函数包含了外部该变量的引用,这个过程称之为函数的闭包。这种情况下,变量值的变化将会影响函数的执行,同样函数执行的过程中改变了变量的值,也会影响其他位置对变量的使用。甚至在一些极端情况下,变量所在的环境已经被释放,但是由于函数中包含对它的引用,变量依然会存在,阻止了对象的释放,造成内存泄露的问题。所以闭包不是一项技术,而是一种现象
 

 

(二)案例演示

任务:演示闭包

  • net.cl.day08包里创建Example12对象
    package net.cl.day08
    
    /**
     * 功能:演示闭包
     * 作者:cl
     * 日期:2023年03月30日
     */
    object Example12 {
      def main(args: Array[String]): Unit = {
        var x = 100
    
        def sum(n: Int): Int = {
          var sum = 0
          var flag = true
          for (i <- 1 to n if flag) {
            sum = sum + i
            if (x > 50) {
              flag = false
            }
          }
          x = 0
          sum
        }
    
        println("x = " + x)
        println("sum = " + sum(100))
        println("x = " + x)
    
        x = 25
        println("x = " + x)
        println("sum = " + sum(100))
        println("x = " + x)
      }
    }
    

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值