spark基础学习笔记13:scala函数(代码片段)

howard2005 howard2005     2022-12-02     143

关键词:

文章目录

零、本讲学习目标

  1. 掌握如何声明函数
  2. 了解各种类型的函数
  3. 掌握占位符的使用
  4. 理解闭包的现象
  5. 掌握可变参数
  6. 理解尾递归

一、声明函数

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

(一)显式声明函数

1、声明格式

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

2、注意事项

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

3、案例演示

  • 创建net.hw.func包,在包里创建Example01对象
package net.hw.func

import scala.io.StdIn

/**
  * 功能:显式声明函数
  * 作者:华卫
  * 日期:2022年03月06日
  */
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)
  

  • 运行程序,查看结果

(二)隐式声明函数

1、声明格式

(参数列表) => 函数体

2、注意事项

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

3、案例演示

  • net.hw.func包里创建Example02对象
package net.hw.func

import scala.io.StdIn

/**
  * 功能:隐式声明函数
  * 作者:华卫
  * 日期:2022年03月06日
  */
object Example02 
  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.readLine().toInt
    print("b = ")
    val b = StdIn.readLine().toInt

    println(a + " + " + b + " = " + add1(a, b))
    println(a + " + " + b + " = " + add2(a, b))
    println(a + " + " + 1 + " = " + add3(a))
  

val add1 = (a: Int, b: Int) => a + b

  • 功能:将函数直接量(a: Int, b: Int) => a + b赋给常量add1

  • 运行程序,查看结果

二、Scala函数种类

(一)成员方法

1、基本概念

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

2、案例演示

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

  • 在项目根目录里创建文本文件test.txt
  • net.hw.func包里创建Example03对象
package net.hw.func

import scala.io.Source

/**
  * 功能:显示文件中长度超过15的行
  * 作者:华卫
  * 日期:2022年03月06日
  */
object Example03 
  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("test.txt", 15)
    for (line <- lines) println(line + " " + line.length)
  


  • 运行程序,查看结果

(二)局部函数

1、基本概念

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

2、案例演示

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

  • net.hw.func包里创建Example04对象
package net.hw.func

import scala.io.Source

/**
  * 功能:采用局部函数显示文件中长度超过15的行
  * 作者:华卫
  * 日期:2022年03月06日
  */
object Example04 
  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("test.txt", 15)
    for (line <- lines) println(line + " " + line.length)
  

  • 函数filter就是函数getLinesFromFile的内嵌函数或本地函数,只能在getLinesFromFile函数内部使用,但是在main方法里是无法访问到filter函数的。

  • 运行程序,查看结果

(三)匿名函数

1、基本概念

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

2、案例演示

任务:将函数赋值给常量

  • net.hw.func包里创建Example05对象
package net.hw.func

/**
  * 功能:将函数赋值给常量
  * 作者:华卫
  * 日期:2022年03月06日
  */
object Example05 
  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.hw.func包里创建Example06对象
package net.hw.func

/**
  * 功能:演示函数作为函数的参数
  * 作者:华卫
  * 日期:2022年03月06日
  */
object Example06 
  def printStr: (String) => Unit = 
    x => println(x)
  

  def main(args: Array[String]): Unit = 
    val cities = List("北京", "上海", "深圳", "泸州")
    cities.foreach(printStr)
  

  • 匿名函数x => println(x)作为函数printStr的返回值。
  • 函数printStr作为列表对象cities的foreach方法的实参。
  • 运行程序,查看结果

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

  • net.hw.func包里创建Example07对象
package net.hw.func

/**
  * 功能:演示函数作为函数的返回值
  * 作者:华卫
  * 日期:2022年03月06日
  */
object Example07 
  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 = 
    cook("鸡肉")
  

  • 运行程序,查看结果

三、神奇占位符

(一)基本概念

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

(二)案例演示

任务1、演示过滤集合

  • net.hw.func包里创建Example08对象
package net.hw.func

/**
  * 功能:过滤集合
  * 作者:华卫
  * 日期:2022年03月06日
  */
object Example08 
  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))
  

  • 运行程序,查看结果
  • 注意:list.filter(_ % 2 == 0)

任务2、演示处理集合

  • net.hw.func包里创建Example09对象
package net.hw.func

/**
  * 功能:处理集合
  * 作者:华卫
  * 日期:2022年03月06日
  */
object Example09 
  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.hw.func包里创建Example10对象
package net.hw.func

/**
  * 功能:参数占位符
  * 作者:华卫
  * 日期:2022年03月06日
  */
object Example10 
  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.hw.func包里创建Example11对象
package net.hw.func

/**
  * 功能:演示闭包
  * 作者:华卫
  * 日期:2022年03月06日
  */
object Example11 
  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)
  


  • 运行程序,查看结果

五、可变参数

(一)基本概念

  • 在Scala中,可以指明函数的最后一个参数是重复的。从而允许客户向函数传入可变参数的列表。想要标注一个重复参数,可以在参数的类型之后放一个星号。
def echo(args :String *) = for (arg <- args) println(arg)
  • 调用:echo("aaa","bbb","ccc")echo("泸州","成都","北京", "上海")
  • 在函数内部,重复参数(可变参数)的类型是声明参数类型的数组

(二)案例演示

任务1、演示可变参数

  • net.hw.func包里创建Example12对象
package net.hw.func

/**
  * 功能:演示可变参数
  * 作者:华卫
  * 日期:2022年03月06日
  */
object Example12 
  def sum(nums: Int*): Int = 
    var sum = 0
    for (num <- nums) 
      sum = sum + num
    
    sum
  

  def main(args: Array[String]): Unit = 
    println(sum(1))
    println(sum(1, 2查看详情  

spark基础学习笔记09:scala基础(代码片段)

...模式。下面我们将在Scala的命令行操作模式中学习Scala的基础知识。一、变量声明(一)简单说明Scala中变量的声明使用关键字val和var。val类似Java中的final变量,也就是常量,一旦初始化将 查看详情

spark基础学习笔记10:scala集成开发环境(代码片段)

...境会在两种集成开发环境里创建Scala项目在上一讲《Spark基础学习笔记09:Scala基础》里,我们都是利用ScalaShell交互式环境来学习Scala基础知识,虽然交互式有快捷的优点,但是要写比较完整的程序,编辑就显得... 查看详情

spark基础-scala学习(集合)(代码片段)

集合scala的集合体系结构ListLinkedListSet集合的函数式编程函数式编程综合案例:统计多个文本内的单词总数scala的集合体系结构scala中的集合体系主要包括:Iterable、Seq、Set、Map。其中Iterable是所有集合trait的根trait。这个结构与java... 查看详情

spark基础学习笔记12:scala内建控制结构

文章目录零、本讲学习目标一、条件表达式(一)语法格式(二)执行情况(三)案例演示任务1、根据输入值的不同进行判断任务2、编写Scala程序,判断奇偶性二、块表达式(一)语法格式ÿ... 查看详情

三万字,spark学习笔记(代码片段)

Spark基础Spark特性Spark使用简练优雅的Scala语言编写,基于Scala提供了交互式编程体验,同时提供多种方便易用的API。Spark遵循“一个软件栈满足不同应用场景”的设计理念,逐渐形成了一套完整的生态系统(包括Spar... 查看详情

spark基础-scala学习(七类型参数)(代码片段)

类型参数是什么类似于java泛型,泛型类泛型函数上边界Bounds下边界ViewBoundsContextBoundsManifestContextBounds协变和逆变ExistentialType泛型类scala>:paste//Enteringpastemode(ctrl-Dtofinish)classStudent[T](vallocalId:T)defgetSchoolId(hukouId:T)="S-"+hukouId+"-"+localId... 查看详情

spark基础-scala学习(代码片段)

Scala解析器的使用REPL:Read(取值)->Evaluation(求值)->Print(打印)->Loop(循环)。scala解析器也被称为REPL,会快速编译scala代码为字节码,然后交给JVM执行valresult=1设置变量不可变varresult=2可变的变量valname:String=null声明变... 查看详情

spark基础学习笔记22:sparkrdd案例分析

文章目录零、本讲学习目标一、案例分析:SparkRDD实现单词计数(一)案例概述(二)实现步骤1、新建Maven管理的Spark项目2、添加Scala和Spark依赖3、创建WordCount对象4、对于程序代码进行解析5、将Spark项目编译和... 查看详情

spark基础学习笔记14:scala数据结构(代码片段)

文章目录零、本讲学习目标一、数组(Array)(一)定长数组1、数组定义(1)定义数组时初始化数据(2)定义时指定数组长度,后赋值2、数组遍历(1)传统for循环方式(2)增强for循环方... 查看详情

spark基础-scala学习(代码片段)

面向对象编程之Traittrait基础知识将trait作为接口使用在trait中定义具体方法在trait中定义具体字段在trait中定义抽象字段trait高级知识为实例对象混入traittrait调用链在trait中覆盖抽象方法混合使用trait的具体方法和抽象方法trait的构... 查看详情

三万字,spark学习笔记

Spark基础Spark特性Spark使用简练优雅的Scala语言编写,基于Scala提供了交互式编程体验,同时提供多种方便易用的API。Spark遵循“一个软件栈满足不同应用场景”的设计理念,逐渐形成了一套完整的生态系统(包括Spar... 查看详情

大数据spark学习:scala基础第一课

计划:阶段1:精通Spark内核阶段2:精通千万级的项目阶段3:机器学习JAVA本身不是伟大的语言,伟大的是JVM,构件分布式平台什么的,依赖的是JVM,不一定要JAVA语言可认为Scala是JAVA的升级语言,JAVA是支持面向对象的语言,而非... 查看详情

scala学习笔记一之基础语法,条件控制,循环控制,函数,数组,集合

...安装教程:http://www.cnblogs.com/biehongli/p/8065679.html1:Scala之基础语法学习笔记:1:声明val变量:可以使用val来声明变量,用来存放表达式的计算结果,但是常量声明后是无法改变它的值的,建议使用val来声明常量;声明var变量:如果要... 查看详情

scala学习笔记编程基础

强烈推荐参考该课程:http://www.runoob.com/scala/scala-tutorial.html1.  Scala概述1.1. 什么是ScalaScala是一种多范式的编程语言,其设计的初衷是要集成面向对象编程和函数式编程的各种特性。Scala运行于Java平台(Java虚拟机),并... 查看详情

scala基础函数(代码片段)

1.前言为什么要学习Scala分布式高并发语言Go、R、Erlang等等为何选择Scala?Spark是大数据处理的核心方式,用scala语言编写!Kafka分布式发布订阅消息系统,由LinkedIn捐给Apache,以极高的吞吐量著称,是目前最... 查看详情

学习笔记spark——配置sparkidea开发环境(代码片段)

一、配置Spark开发环境1.1、配置Spark开发依赖包创建一个Scala工程(scala插件及工程创建教程:https://www.cnblogs.com/frankdeng/p/9092512.html)点击菜单栏中的“File”->“ProjectStructure”,打开右上图所示的界面选择“Librari... 查看详情

spark基础学习笔记02:搭建spark环境(代码片段)

文章目录零、本讲学习目标一、搭建Spark单机版环境(一)在私有云上创建ied实例(二)修改ied实例的主机名(三)设置IP地址与主机名的映射(四)通过SecureCRT访问ied虚拟机(五)下载、安... 查看详情