• 【Scala专栏】方法和函数


    开篇词:这个章节会很烧脑,需要认真研读,我会尽量写的详细一些。 方法和函数,看似是两个概念,其实他严格来说也是两个概念,但我们大可以理解成是同一个概念,在使用时只有语法上的细微差别,是很类似的,都理解为function即可。

    一、方法的定义

    1.方法体中最后返回值可以使用return, 如果使用了return, 那么方法体的返回值类型一定要指定
    2.如果方法体重没有return, 默认将 方法体中最后一行计算的结果当作返回值返回. 方法体的返回值可以省略, 会自动推断
    3.定义方法传入的参数一定要指定类型
    4.方法的方法体如果只有一行, 那么方法体的“{…}”可以省略
    5.如果定义方法时, 省略了方法名称和方法体之间的"=", 那么无论方法体最后一行计算的结果是什么, 都会被丢弃, 返回Unit

    def max(a: Int, b: Int) = {
      if (a > b) {
        "哈哈"
      } else {
        b
      }
    }
    
    // 语法糖: 方法定义
    def max0(a: Int, b: Int) = if (a > b) a else b
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    笔者注:记住def定义的格式,按着格式敲即可,不要纠结

    二、递归方法

    递归方法必须要显示指定返回体的类型

    def fun2(num: Int): Int = {
      if (num == 1)
        num
      else
        num * fun2(num - 1)
    }
    // 语法糖
    def fun2(num:Int) : Int = if (num == 1) num else num * fun2(num - 1)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    笔者注:编译器无法直接推断出你最终递归的结果类型,所以需要你显示指定

    三、参数有默认值的方法

    1.默认值的函数中,如果传入的参数个数与函数定义相同,则传入的数值会覆盖默认值
    2.如果不想覆盖默认值,传入的参数个数小于定义的函数的参数,则需要指定参数名称

    def fun3(a: Int = 10, b: Int) = {
      println(a + b)
    }
    
    • 1
    • 2
    • 3

    四、可变参数个数的函数

    多个参数之间逗号分开

    def fun4(elements: Int*) = {
      println(elements)
      elements.foreach(i => println(i))
      // 当匿名函数的元素只用到一次的时候, 可以用_简写
      elements.foreach(println(_))
      // 当方法入参为单个参数时且正好是匿名函数的元素时, 进一步简写
      elements.foreach(println)
      var sum = 0;
      for (elem <- elements) {
        sum += elem
      }
      sum
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    五、匿名函数

    注意函数的写法与方法的写法有些许的不同,出现 => 符号就认为是函数,但实际使用上效果并无不同,仅仅是语法上的细微区别

    原生的匿名函数写法(基本不用):(Int, Int) => Int就是他的类型

    /**
     * 原生的匿名函数写法(基本不用)
     * @return
     */
    def fun: (Int, Int) => Int = (a: Int, b: Int) => {
      a + b
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    常用的匿名函数写法: 可以将匿名函数返回给定义的一个变量, 看到“=>”就是匿名函数, 多用于方法的参数是函数时(函数指针),用匿名函数简写

    /**
     * 常用的匿名函数写法: 可以将匿名函数返回给定义的一个变量, 看到“=>”就是匿名函数
     * 多用于方法的参数是函数时(函数指针),用匿名函数简写
     *
     * @param args
     */
    def main(args: Array[String]): Unit = {
    
      /**
       * 有参数匿名函数
       */
      val value1: (Int) => Unit = (a: Int) => {
        println(a)
      }
      value1(1)
    
      /**
       * 无参数匿名函数
       */
      val value2 = () => {
        println("我爱学习")
      }
      value2()
    
      /**
       * 有返回值的匿名函数
       */
      val value3 = (a: Int, b: Int) => {
        a + b
      }
      println(value3(4, 4))
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    六、嵌套方法

    /**
     * 嵌套方法
     * 例如:嵌套方法求5的阶乘
     */
    def fun5(num: Int) = {
      def fun6(a: Int, b: Int): Int = {
        if (a == 1) {
          b
        } else {
          fun6(a - 1, a * b)
        }
      }
      fun6(num, 1)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    七、偏应用函数(部分应用函数)

    某些情况下, 方法中参数非常多, 调用这个方法非常频繁, 每次调用只有固定的某个参数变化, 其他都不变, 可以定义偏应用来实现

    def showLog(date :Date, log :String)= {
      println(s"date is $date, log is $log")
    }
    
    def main(args: Array[String]): Unit = {
      val date = DateUtil.date(new Date())
      showLog(date,"当前时间")
      // 想要调用log, 以上变化的是第二个参数, 可以用偏应用函数处理
      // 把showLog()方法定义为偏应用函数
      val logWithDate = showLog(date,_:String)
      // 第二种函数写法
      def logWithDate2 = showLog(date,_:String)
      logWithDate("偏应用函数-log11")
      logWithDate("偏应用函数-log22")
      logWithDate("偏应用函数-log33")
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    八、高阶函数

    函数的参数是函数,或者函数的返回类型是函数,或者函数的参数和函数的返回类型是函数的函数.

      /**
       * 普通的方法
       *
       * @param a
       * @param b
       * @return
       */
      def fun(a: Int, b: Int): Int = {
        a + b
      }
    
      /**
       * 使用 _把方法强转为一个函数
       */
      private val function: (Int, Int) => Int = fun _
    
      /**
       * 函数的参数是函数: 函数的类型 (Int, Int) => Int, 记住: 方法的引用仅为方法本身,需要重新赋实参
       *
       * @param f 函数作为参数
       * @param a
       * @return
       */
      def fun1(f: (Int, Int) => Int, a: Int): Int = {
        f(a, 100)
      }
    
      /**
       * 函数的返回是函数: 必须要显示地写出返回值类型, 或者使用 f2 _
       *
       * @param a
       * @param b
       * @return
       */
      def fun2(a: Int, b: Int): (Int, Int) => Int = {
        // 在内部定义了一个方法
        def f2(v1: Int, v2: Int): Int = {
          v1 + v2 + a + b
        }
    
        f2
      }
    
      /**
       * 函数的参数是函数,函数的返回是函数
       *
       * @param f
       * @return
       */
      def fum3(f: (Int, Int) => Int): (String, String) => String = {
        val i = f(1, 2)
    
        def fun1(s1: String, s2: String): String = {
          s1 + "@" + s2 + "$" + i
        }
    
        fun1
      }
    
    
      /**
       * 函数入口
       *
       * @param args
       */
      def main(args: Array[String]): Unit = {
        // 显示声明过的函数作为参数
        println("显示声明过的函数作为参数: " + fun1(fun, 100))
        // 匿名函数作为参数: 匿名函数入参的类型可以省略不写
        println("匿名函数作为参数: " + fun1((a: Int, b: Int) => {
          a * b
        }, 100))
        // 返回值是一个函数
        println("返回值是一个函数: " + fun2(1, 2)(3, 4))
        // 入参和出参都是函数
        println("入参和出参都是函数: " + fum3(fun)("hello", "scala!"))
        println("入参和出参都是函数: " + fum3((a, b) => a * b)("hello", "scala!"))
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78

    笔者注:高阶函数这块内容会相对较为难以理解,可以先记住这种结构

    九、柯里化函数

    柯里化函数: 本质上就是对返回值是函数的方法的一种简化写法

    def fun7(a: Int, b: Int)(c: Int, d: Int) = {
      a + b + c + d
    }
    
    /**
     * 函数入口
     *
     * @param args
     */
    def main(args: Array[String]): Unit = {
      println(fun7(1, 2)(3, 4))
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    笔者注:fun7(1, 2)(3, 4)可以理解成先运算fun7(1,2)返回了一个fun7函数对象,再对他进行参数(3,4)的赋值

    结语:本篇章的内容就这么多,Scala作为一门函数式的语言,函数这块自然是重点内容,要好好学习哦,我们下期再见!

  • 相关阅读:
    java selenium (五) 元素定位大全
    计算机组成原理_笔记_第4章:指令系统
    超级好用绘图工具(Draw.io+Github)
    代码随想录算法训练营第五十一天| 121. 买卖股票的最佳时机 122.买卖股票的最佳时机II
    Java Field类简介说明
    广东海洋大学计算机考研资料汇总
    java 位运算 + leetcode 22.8.3 前n个数字二进制中1的个数
    03——go开发工具
    视频 | 生信Linux - Linux下文件内容操作03
    学习Opencv(蝴蝶书/C++)——1. 前言 和 第1章.概述
  • 原文地址:https://blog.csdn.net/haohaoxuexiyai/article/details/128131070