Spark基础学习笔记13:Scala函数
Posted howard2005
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spark基础学习笔记13:Scala函数相关的知识,希望对你有一定的参考价值。
文章目录
零、本讲学习目标
- 掌握如何声明函数
- 了解各种类型的函数
- 掌握占位符的使用
- 理解闭包的现象
- 掌握可变参数
- 理解尾递归
一、声明函数
- 函数其实是一段具有特定功能的代码的集合,由函数修饰符、函数名、函数参数列表、函数返回值声明与函数体组成。
(一)显式声明函数
1、声明格式
[public | private | protected] def 函数名(参数列表) : 返回值声明 = 函数体
2、注意事项
- 函数通过
def
关键字定义 def
前面可以具有修饰符,可以通过private
、protected
来控制其访问权限。注意默认访问权限是public
- 还可使用
override
、final
等关键字修饰 - 函数体中
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, 2Spark基础学习笔记04:Scala简介与安装