文章目录
第二章 变量和数据类型
(一)注释
- Scala 注释使用和 Java 完全一样。
- 注释是一个程序员必须要具有的良好编程习惯。将自己的思想通过注释先整理出来,再
用代码去体现
1、基本语法
(1)单行注释://
(2)多行注释:/* */
(3)文档注释:/**
*
*/
2、案例
package net.cch.scala.day01
/**
* 功能: 注释
* 作者: 陈春宏
* 时间: 2022年06月10日
*/
object TestNotes {
def main(args: Array[String]): Unit = {
//(1)单行注释://
println("dalang")
//(2)多行注释:/* */
/*
println("dalang")
println("jinlian")
*/
//(3)文档注释:/**
//*
//*/
/**
* println("qingge")
* println("qingge")
* p
*/
}
}
(二)变量和常量
- 常量:在程序执行的过程中,其值不会被改变的变量
1、基本语法
- var 变量名 [: 变量类型] = 初始值 var i:Int = 10
- val 常量名 [: 常量类型] = 初始值 val j:Int = 20
- 注意:能用常量的地方不用变量
2、案例
- var 变量
package net.cch.scala.day01
/**
* 功能: var变量
* 作者: 陈春宏
* 时间: 2022年06月10日
*/
object TestVar {
def main(args: Array[String]): Unit = {
//(1)声明变量时,类型可以省略,编译器自动推导,即类型推导
var age = 18
age = 30
//(2)类型确定后,就不能修改,说明 Scala 是强数据类型语言。
// age = "tom" // 错误
//(3)变量声明时,必须要有初始值
// var name //错误
//(4)在声明/定义一个变量时,可以使用 var 或者 val 来修饰,var 修饰 的变量可改变,val 修饰的变量不可改。
var num1 = 10 // 可变
val num2 = 20 // 不可变
num1 = 30 // 正确
//num2 = 100 //错误,因为 num2 是 val 修饰的
}
}
- val 常量
package net.cch.scala.day01
/**
* 功能: val常量
* 作者: 陈春宏
* 时间: 2022年06月10日
*/
object TestVal {
def main(args: Array[String]): Unit = {
// p1 是 var 修饰的,p1 的属性可以变,而且 p1 本身也可以变
var p1 = new Person()
p1.name = "dalang"
p1 = null
// p2 是 val 修饰的,那么 p2 本身就不可变(即 p2 的内存地址不能变), 但是,p2 的属性是可以变,因为属性并没有用 val 修饰。
val p2 = new Person()
p2.name="jinlian"
// p2 = null // 错误的,因为 p2 是 val 修饰的
}
}
class Person{
var name : String = "jinlian"
}
(三)标识符
- Scala 对各种变量、方法、函数等命名时使用的字符序列称为标识符。即:凡是自己可
以起名字的地方都叫标识符。
1、命名规则
(1)以字母或者下划线开头,后接字母、数字、下划线
(2)以操作符开头,且只包含操作符(+ - * / # !等)
(3)用反引号`....`包括的任意字符串,即使是 Scala 关键字(39 个)也可以
(四)数据类型
- 在Scala中,所有的值都有一个类型,包括数值和函数。如下图所示,说明了Scala的类型层次结构
1、Any类型
- Any是Scala类层次结构的根,也被称为超类或顶级类。Scala执行环境中的每个类都直接或间接地从该类继承。该类中定义了一些通用的方法,例如equals()、hashCode()和toString()。Any有两个直接子类:AnyVal和AnyRef。
2、AnyVal类型
AnyVal表示值类型,有9种预定义的值类型,它们是非空的Double、Float、Long、Int、Short、Byte、Char、Unit和Boolean。Unit是一个不包含任何信息的值类型,和Java语
3、AnyRef类型
- AnyRef表示引用类型。所有非值类型都被定义为引用类型。Scala中的每个用户定义类型都是AnyRef的子类型。AnyRef对应于Java中的java.lang.Object。
4、整数类型(Byte、Short、Int、Long)
- Scala 各整数类型有固定的表示范围和字段长度,不受具体操作的影响,以保证
Scala 程序的可移植性。
(1)案例
package net.cch.scala.day01
/**
* 功能: 整数类型
* 作者: 陈春宏
* 时间: 2022年06月10日
*/
object TestDataType {
def main(args: Array[String]): Unit = {
// 正确
var n1:Byte = 127
var n2:Byte = -128
// 错误
// var n3:Byte = 128
// var n4:Byte = -129
//Scala 的整型,默认为 Int 型,声明 Long 型,须后加‘l’或‘L’
var n5 = 10
println(n5)
var n6 = 9223372036854775807L
println(n6)
}
}
5、浮点类型
- Scala 的浮点类型可以表示一个小数,比如 123.4f,7.8,0.12 等等。
(1)案例
package net.cch.scala.day01
/**
* 功能: 浮点类型
* 作者: 陈春宏
* 时间: 2022年06月10日
*/
object TestDateType1 {
def main(args: Array[String]): Unit = {
// 建议,在开发中需要高精度小数时,请选择 Double
var n7 = 2.2345678912f
var n8 = 2.2345678912
println("n7=" + n7)
println("n8=" + n8)
}
}
- 查看结果
6、字符类型
(1)基本说明
- 字符类型可以表示单个字符,字符类型是 Char。
(2)案例
package net.cch.scala.day01
/**
* 功能: char类型
* 作者: 陈春宏
* 时间: 2022年06月10日
*/
object TestCharType {
def main(args: Array[String]): Unit = {
//(1)字符常量是用单引号 ' ' 括起来的单个字符。
var c1: Char = 'a'
println("c1=" + c1)
//注意:这里涉及自动类型提升,其实编译器可以自定判断是否超出范围,
//不过 idea 提示报错
var c2:Char = 'a' + 1
println(c2)
//(2)\t :一个制表位,实现对齐的功能
println("姓名\t 年龄")
//(3)\n :换行符
println("牛郎\n 织女")
//(4)\\ :表示\
println("D\\scala\\bin")
//(5)\" :表示"
println("大数据必学:\"学习scala\"")
}
}
7、布尔类型
(1)基本说明
- 布尔类型也叫 Boolean 类型,Booolean 类型数据只允许取值 true 和 false
- boolean 类型占 1 个字节。
(2)案例
package net.cch.scala.day01
/**
* 功能: Boolean类型
* 作者: 陈春宏
* 时间: 2022年06月10日
*/
object TestBooleanType {
def main(args: Array[String]): Unit = {
var isResult : Boolean = false
var isResult2 : Boolean = true
}
}
8、Unit 类型、Null 类型和 Nothing 类型
(1)基本说明
- Unit:表示无值,和其他语言中 void 等同。用作不返回任何结果的方法的结果
类型。Unit 只有一个实例值,写成()。 - Null :null , Null 类型只有一个实例值 null
- Nothing :Nothing 类型在 Scala 的类层级最低端;它是任何其他类型的子类型。
当一个函数,我们确定没有正常的返回值,可以用 Nothing 来指定返回类
型,这样有一个好处,就是我们可以把返回的值(异常)赋给其它的函数
或者变量(兼容性)
(2)案例
- Unit
package net.cch.scala.day01
/**
* 功能: Unit类型
* 作者: 陈春宏
* 时间: 2022年06月10日
*/
object TestUnitType {
def main(args: Array[String]): Unit = {
def sayOk : Unit = {// unit 表示没有返回值,即 void
}
println(sayOk)
}
}
- Null
package net.cch.scala.day01
/**
* 功能: Null类型
* 作者: 陈春宏
* 时间: 2022年06月10日
*/
object TestNullType {
def main(args: Array[String]): Unit = {
//null 可以赋值给任意引用类型(AnyRef),但是不能赋值给值类型 (AnyVal)
var cat = new Cat();
cat = null // 正确
var n1: Int = null // 错误
println("n1:" + n1)
}
}
class Cat{
}
- Nothing
package net.cch.scala.day01
/**
* 功能: Nothing类型
* 作者: 陈春宏
* 时间: 2022年06月10日
*/
object TestNothingType {
def main(args: Array[String]): Unit = {
def test() : Nothing={
throw new Exception()
}
test
}
}
第三章 运算符
(一)算术运算符
1、基本语法
2、案例
package net.cch.scala.day01
/**
* 功能: 算术运算符
* 作者: 陈春宏
* 时间: 2022年06月10日
*/
object TestArithmetic {
def main(args: Array[String]): Unit = {
//(1)对于除号“/”,它的整数除和小数除是有区别的:整数之间做除法 时,只保留整数部分而舍弃小数部分。
var r1: Int = 10 / 3 // 3
println("r1=" + r1)
var r2: Double = 10 / 3 // 3.0
println("r2=" + r2)
var r3: Double = 10.0 / 3 // 3.3333
println("r3=" + r3)
println("r3=" + r3.formatted("%.2f")) // 含义:保留小数点 2位,使用四舍五入
//(2)对一个数取模 a%b,和 Java 的取模规则一样。
var r4 = 10 % 3 // 1
println("r4=" + r4)
}
}
(二)关系运算符
1、基本语法
2、案例
package net.cch.scala.day01
/**
* 功能: 关系运算符
* 作者: 陈春宏
* 时间: 2022年06月10日
*/
object TestRelation {
def main(args: Array[String]): Unit = {
// 测试:>、>=、<=、<、==、!=
var a: Int = 2
var b: Int = 1
println(a > b) // true
println(a >= b) // true
println(a <= b) // false
println(a < b) // false
println("a==b" + (a == b)) // false
println(a != b) // true
}
}
(三)逻辑运算符
1、基本语法
package net.cch.scala.day01
/**
* 功能: 逻辑运算符
* 作者: 陈春宏
* 时间: 2022年06月10日
*/
object TestLogic {
def main(args: Array[String]): Unit = {
// 测试:&&、||、!
var a = true
var b = false
println("a&&b=" + (a && b)) // a&&b=false
println("a||b=" + (a || b)) // a||b=true
println("!(a&&b)=" + (!(a && b))) // !(a&&b)=true
}
}
(四)赋值运算符
1、基本语法
2、案例
package net.cch.scala.day01
/**
* 功能: 赋值运算符
* 作者: 陈春宏
* 时间: 2022年06月10日
*/
object TestAssignment {
def main(args: Array[String]): Unit = {
var r1 = 10
r1 += 1 // 没有++
r1 -= 2 // 没有--
}
}
(五) 位运算符
1、基本语法
2、案例
package net.cch.scala.day02
/**
* 功能: 位运算
* 作者: 陈春宏
* 时间: 2022年06月10日
*/
object TestPosition {
def main(args: Array[String]): Unit = {
// 测试:1000 << 1 =>10000
var n1 :Int =8
n1 = n1 << 1
println(n1)
}
}
第四章 流程控制
(一)分支控制if-else
- 让程序有选择的的执行,分支控制有三种:单分支、双分支、多分支
1、单分支
(1)基本语法
if (条件表达式) {
执行代码块
}
(2) 案例
package net.cch.scala.day02
import scala.io.StdIn
/**
* 功能: 单分支
* 作者: 陈春宏
* 时间: 2022年06月10日
*/
object TestIf_else01 {
def main(args: Array[String]): Unit = {
//需求:输入人的年龄,如果该同志的年龄小于 18 岁,则输出“童年”
println("input age:")
var age = StdIn.readShort()
if (age < 18){
println("童年")
}
}
}
2、双分支
(1)基本语法
if (条件表达式) {
执行代码块 1
} else {
执行代码块 2
}
(2) 案例
package net.cch.scala.day02
import scala.io.StdIn
/**
* 功能: 双分支
* 作者: 陈春宏
* 时间: 2022年06月10日
*/
object TestIfElse02 {
def main(args: Array[String]): Unit = {
//需求:输入年龄,如果年龄小于 18 岁,则输出“童年”。否则,输出“成年”。
println("input age:")
var age = StdIn.readShort()
if (age < 18){
println("童年")
}else{
println("成年")
}
}
}
3、多分支
(1)基本语法
if (条件表达式 1) {
执行代码块 1
}
else if (条件表达式 2) {
执行代码块 2
}
……
else {
执行代码块 n
}
(2) 实操
package net.cch.scala.day02
import scala.io.StdIn
/**
* 功能: 多分支
* 作者: 陈春宏
* 时间: 2022年06月10日
*/
object TestIfElse03 {
def main(args: Array[String]): Unit = {
//需求 1:需求:输入年龄,如果年龄小于 18 岁,则输出“童年”。如果年龄大于等于 18 且小于等于 30,则输出“中年”,否则,输出“老年”。
println("input age")
var age = StdIn.readInt()
if (age < 18){
println("童年")
}else if(age>=18 && age<30){
println("中年")
}else{
println("老年")
}
}
}
(二) for循环
- Scala 也为 for 循环这一常见的控制结构提供了非常多的特性,这些 for 循环的特性被称
为 for 推导式或 for 表达式。
1、范围数据循环(To)
(1)基本语法
for(i <- 1 to 3){
print(i + " ")
}
println()
(2) 案例
package net.cch.scala.day02
import sun.applet.Main
/**
* 功能: for循环
* 作者: 陈春宏
* 时间: 2022年06月10日
*/
object TestFor01 {
def main(args: Array[String]): Unit = {
for(i <- 1 to 5){
println("Hello World"+i)
}
}
}
2、范围数据循环(Until)
(1)基本语法
for(i <- 1 until 3) {
print(i + " ")
}
println()
(2)案例
package net.cch.scala.day02
/**
* 功能: Until
* 作者: 陈春宏
* 时间: 2022年06月10日
*/
object TestFor02 {
def main(args: Array[String]): Unit = {
for(i <- 1 until 5 + 1){
println("hello scala" + i)
}
}
}
3、循环守卫
(1)基本语法
for(i <- 1 to 3 if i != 2) {
print(i + " ")
}
println()
-
循环守卫,即循环保护式(也称条件判断式,守卫)。保护式为 true 则进入循环
体内部,为 false 则跳过,类似于 continue。 -
上面的代码等价
for (i <- 1 to 3){
if (i != 2) {
print(i + " ")
}
}
(2)案例
- 需求:输出 1 到 5 中,不等于 3 的值
package net.cch.scala.day03
/**
* 功能: 循环守卫
* 作者: 陈春宏
* 时间: 2022年06月10日
*/
object TestFor {
def main(args: Array[String]): Unit = {
for (i <- 1 to 5 if i != 3) {
println(i + "张三")
}
}
}
4、 循环步长
(1)基本语法
for (i <- 1 to 10 by 2) {
println("i=" + i)
}
- 说明:by表示步长
(2)实操
- 需求:输出 1 到 10 以内的所有奇数
package net.cch.scala.day03
/**
* 功能: 循环步长
* 作者: 陈春宏
* 时间: 2022年06月10日
*/
object TestFor1 {
def main(args: Array[String]): Unit = {
for (i <- 1 to 10 by 2) {
println("i=" + i)
}
}
}
5、嵌套循环
(1)基本语法
for(i <- 1 to 3; j <- 1 to 3) {
println(" i =" + i + " j = " + j)
}
- 说明:没有关键字,所以范围后一定要加;来隔断逻辑
(2)基本语法
- 等价于上面的代码
for (i <- 1 to 3) {
for (j <- 1 to 3) {
println("i =" + i + " j=" + j)
}
}
6、引入变量
(1)基本语法
for(i <- 1 to 3; j = 4 - i) {
println("i=" + i + " j=" + j)
}
- for 推导式一行中有多个表达式时,所以要加 ; 来隔断逻辑
- for 推导式有一个不成文的约定:当 for 推导式仅包含单一表达式时使用圆括号,
当包含多个表达式时,一般每行一个表达式,并用花括号代替圆括号,如下
for {
i <- 1 to 3
j = 4 - i
} {
println("i=" + i + " j=" + j)
}
(2)案例
- 上面的代码等价于
for (i <- 1 to 3) {
var j = 4 - i
println("i=" + i + " j=" + j)
}
7、循环返回值
(1)基本语法
val res = for(i <- 1 to 10) yield i
println(res)
- 将遍历过程中处理的结果返回到一个新 Vector 集合中,使用 yield 关键字。
(2)实操
- 需求:将原数据中所有值乘以 2,并把数据返回到一个新的集合中。
package net.cch.scala.day03
/**
* 功能: 循环返回值
* 作者: 陈春宏
* 时间: 2022年06月10日
*/
object TestFor2 {
def main(args: Array[String]): Unit = {
var res = for(i <-1 to 10) yield {
i * 2
}
println(res)
}
}
8、倒序打印
(1)如果想倒序打印一组数据,可以用 reverse。
(2)实操:
- 需求:倒序打印 10 到 1
package net.cch.scala.day03
import scala.language.postfixOps
/**
* 功能: 倒序打印
* 作者: 陈春宏
* 时间: 2022年06月10日
*/
object TestFor3 {
def main(args: Array[String]): Unit = {
for(i <- 1 to 10 reverse){
println(i)
}
}
}
(三)While循环控制
1、基本语法
循环变量初始化
while (循环条件) {
循环体(语句)
循环变量迭代
}
- 循环条件是返回一个布尔值的表达式
- while 循环是先判断再执行语句
- 与 for 语句不同,while 语句没有返回值,即整个 while 语句的结果是 Unit 类型()
- 因为 while 中没有返回值,所以当要用该语句来计算并返回结果时,就不可避免
的使用变量,而变量需要声明在 while 循环的外部,那么就等同于循环的内部对外部的变量
造成了影响,所以不推荐使用,而是推荐使用 for 循环。
2、案例
- 需求:输出10句“I LOVE YOU”
package net.cch.scala.day03
/**
* 功能: While循环
* 作者: 陈春宏
* 时间: 2022年06月10日
*/
object TestWhile {
def main(args: Array[String]): Unit = {
var i = 0
while (i < 10) {
println("I LOVE YOU" + i)
i += 1
}
}
}
(四)do…while 循环控制
(1)基本语法
循环变量初始化;
do{
循环体(语句)
循环变量迭代
} while(循环条件
- 循环条件是返回一个布尔值的表达式
- do…while 循环是先执行,再判断
(2)案例
- 需求:输出 10 句 “I LOVE YOU”
package net.cch.scala.day03
/**
* 功能: 循环控制
* 作者: 陈春宏
* 时间: 2022年06月10日
*/
object TestDoWhile {
def main(args: Array[String]): Unit = {
var i = 0
do {
println("宋宋,喜欢海狗人参丸" + i)
i += 1
} while (i < 10)
}
}
(五)循环中断
1、基本说明
- Scala 内置控制结构特地去掉了 break 和 continue,是为了更好的适应函数式编程,推
荐使用函数式的风格解决break和continue的功能,而不是一个关键字。Scala中使用breakable
控制结构来实现 break 和 continue 功能
2、实操
- 需求一:采用异常的方式退出循环
package net.cch.scala.day03
/**
* 功能: 控制循环
* 作者: 陈春宏
* 时间: 2022年06月10日
*/
object TestBreak {
def main(args: Array[String]): Unit = {
try {
for (elem <- 1 to 10) {
println(elem)
if (elem == 5) throw new RuntimeException
}
} catch {
case e =>
}
println("正常结束循环")
}
}
- 需求二:采用异常的方式退出循环
package net.cch.scala.day03
import scala.util.control.Breaks
/**
* 功能: 控制循环
* 作者: 陈春宏
* 时间: 2022年06月10日
*/
object TestBreakS {
def main(args: Array[String]): Unit = {
Breaks.breakable(
for (elem <- 1 to 10) {
println(elem)
if (elem == 5) Breaks.break()
}
)
println("正常结束循环")
}
}
- 需求 3:对 break 进行省略
package net.cch.scala.day03
import scala.util.control.Breaks._
/**
* 功能: 控制循环
* 作者: 陈春宏
* 时间: 2022年06月10日
*/
object TestBreak1 {
def main(args: Array[String]): Unit = {
breakable {
for (elem <- 1 to 10) {
println(elem)
if (elem == 5) break
}
}
println("正常结束循环")
}
}
- 需求 4:循环遍历 10 以内的所有数据,奇数打印,偶数跳过(continue)
package net.cch.scala.day03
/**
* 功能: 控制循环
* 作者: 陈春宏
* 时间: 2022年06月10日
*/
object TestBreak2 {
def main(args: Array[String]): Unit = {
for (elem <- 1 to 10) {
if (elem % 2 == 1) {
println(elem)
} else {
println("continue")
}
}
}
}
(六)多重循环
1、基本说明
- 将一个循环放在另一个循环体内,就形成了嵌套循环。其中,for,while,do…while
均可以作为外层循环和内层循环。【建议一般使用两层,最多不要超过 3 层】 - 设外层循环次数为 m 次,内层为 n 次,则内层循环体实际上需要执行 m*n 次。
2、打印九九乘法表
package net.cch.scala.day03
/**
* 功能: 打印九九乘法表
* 作者: 陈春宏
* 时间: 2022年06月10日
*/
object TestWhile1 {
def main(args: Array[String]): Unit = {
for(i<- 1 to 9){
for(j <- 1 to i){
print(j + "*" + i + "=" + (i * j)+ "\t")
}
println()
}
}
}
第五章 函数式编程
(1)面向对象编程
- 解决问题,分解对象,行为,属性,然后通过对象的关系以及行为的调用来解决问题。
- 对象:用户
- 行为:登录、连接 JDBC、读取数据库
- 属性:用户名、密码
- Scala 语言是一个完全面向对象编程语言。万物皆对象
- 对象的本质:对数据和行为的一个封装
(2)函数式编程
- 解决问题时,将问题分解成一个一个的步骤,将每个步骤进行封装(函数),通过调用
这些封装好的步骤,解决问题。 - 例如:请求->用户名、密码->连接 JDBC->读取数据库
- Scala 语言是一个完全函数式编程语言。万物皆函数。
- 函数的本质:函数可以当做一个值进行传递
(3)在 Scala 中函数式编程和面向对象编程完美融合在一起了
一、函数基础
1、函数基本语法
(1)基本语法
(2)实操
- 需求:定义一个函数,实现将传入的名称打印出来。
package net.cch.scala.day04
/**
* 功能: 函数基本语法
* 作者: 陈春宏
* 时间: 2022/6/20 9:43
*/
object TestFunction {
def main(args: Array[String]): Unit = {
// (1)函数定义
def f(arg: String): Unit = {
println(arg)
}
// (2)函数调用
// 函数名(参数)
f("hello world")
}
}
2、函数和方法的区别
(1)核心概念
- 为完成某一功能的程序语句的集合,称为函数。
- 类中的函数称之方法。
(2)实操
- Scala 语言可以在任何的语法结构中声明任何的语法
- 函数没有重载和重写的概念;方法可以进行重载和重写
- Scala 中函数可以嵌套定义
package net.cch.scala.day04
/**
* 功能: 函数的嵌套
* 作者: 陈春宏
* 时间: 2022/6/20 9:48
*/
package net.cch.scala.day04
/**
* 功能: 函数的嵌套
* 作者: 陈春宏
* 时间: 2022/6/20 9:48
*/
object TestFunction1 {
// (2)方法可以进行重载和重写,程序可以执行
def main(): Unit = {
}
def main(args: Array[String]): Unit = {
// (1)Scala 语言可以在任何的语法结构中声明任何的语法
import java.util.Date
new Date()
// (2)函数没有重载和重写的概念,程序报错
def test(): Unit = {
println("无参,无返回值")
}
test()
// def test(name: String): Unit = {
// println()
// }
//(3)Scala 中函数可以嵌套定义
def test2(): Unit = {
def test3(name: String): Unit = {
println("函数可以嵌套定义")
}
}
}
}
3、函数定义
(1)函数定义
- 函数 1:无参,无返回值
- 函数 2:无参,有返回值
- 函数 3:有参,无返回值
- 函数 4:有参,有返回值
- 函数 5:多参,无返回值
- 函数 6:多参,有返回值
(2)案例
package net.cch.scala.day04
/**
* 功能: 函数定义
* 作者: 陈春宏
* 时间: 2022/6/20 9:53
*/
object TestFunctionDeclare {
def main(args: Array[String]): Unit = {
// 函数 1:无参,无返回值
def test1(): Unit ={
println("无参,无返回值")
}
test1()
// 函数 2:无参,有返回值
def test2():String={
return "无参,有返回值"
}
println(test2())
// 函数 3:有参,无返回值
def test3(s:String):Unit={
println(s)
}
test3("jinlian")
// 函数 4:有参,有返回值
def test4(s:String):String={
return s+"有参,有返回值"
}
println(test4("hello "))
// 函数 5:多参,无返回值
def test5(name:String, age:Int):Unit={
println(s"$name, $age")
}
test5("dalang",40)
}
}
4、函数参数
(1)案例实操
- 可变参数
- 如果参数列表中存在多个参数,那么可变参数一般放置在最后
- 参数默认值,一般将有默认值的参数放置在参数列表的后面
- 带名参数
package net.cch.scala.day04
/**
* 功能: 函数参数
* 作者: 陈春宏
* 时间: 2022/6/20 11:06
*/
object TestFunction2 {
def main(args: Array[String]): Unit = {
// (1)可变参数
def test( s : String* ): Unit = {
println(s)
}
// 有输入参数:输出 Array
test("Hello", "Scala")
// 无输入参数:输出 List()
test()
// (2)如果参数列表中存在多个参数,那么可变参数一般放置在最后
def test2( name : String, s: String* ): Unit = {
println(name + "," + s)
}
test2("jinlian", "dalang")
// (3)参数默认值
def test3( name : String, age : Int = 30 ): Unit = {
println(s"$name, $age")
}
// 如果参数传递了值,那么会覆盖默认值
test3("jinlian", 20)
// 如果参数有默认值,在调用的时候,可以省略这个参数
test3("dalang")
// 一般情况下,将有默认值的参数放置在参数列表的后面
def test4( sex : String = "男", name : String ): Unit = {
println(s"$name, $sex")
}
// Scala 函数中参数传递是,从左到右
//test4("wusong")
//(4)带名参数
test4(name="ximenqing")
}
}
5、函数至简原则(重点)
- 函数至简原则:能省则省
(1)至简原则细节
(1)return 可以省略,Scala 会使用函数体的最后一行代码作为返回值
(2)如果函数体只有一行代码,可以省略花括号
(3)返回值类型如果能够推断出来,那么可以省略(:和返回值类型一起省略)
(4)如果有 return,则不能省略返回值类型,必须指定
(5)如果函数明确声明 unit,那么即使函数体中使用 return 关键字也不起作用
(6)Scala 如果期望是无返回值类型,可以省略等号
(7)如果函数无参,但是声明了参数列表,那么调用时,小括号,可加可不加
(8)如果函数没有参数列表,那么小括号可以省略,调用时小括号必须省略
(9)如果不关心名称,只关心逻辑处理,那么函数名(def)可以省略
(2)案例
package net.cch.scala.day04
/**
* 功能: 函数至简原则
* 作者: 陈春宏
* 时间: 2022/6/20 11:12
*/
object TestFunction3 {
def main(args: Array[String]): Unit = {
// (0)函数标准写法
def f(s: String): String = {
return s + " jinlian"
}
println(f("Hello"))
// 至简原则:能省则省
//(1) return 可以省略,Scala 会使用函数体的最后一行代码作为返回值
def f1(s: String): String = {
s + " jinlian"
}
println(f1("Hello"))
//(2)如果函数体只有一行代码,可以省略花括号
def f2(s: String): String = s + " jinlian"
//(3)返回值类型如果能够推断出来,那么可以省略(:和返回值类型一起 省略)
def f3(s: String) = s + " jinlian"
println(f3("Hello3"))
//(4)如果有 return,则不能省略返回值类型,必须指定。
def f4(): String = {
return "ximenqing4"
}
println(f4())
//(5)如果函数明确声明 unit,那么即使函数体中使用 return 关键字也不起作用
def f5(): Unit = {
return "dalang5"
}
println(f5())
//(6)Scala 如果期望是无返回值类型,可以省略等号
// 将无返回值的函数称之为过程
// def f6() {
// "dalang6"
// }
// println(f6())
//(7)如果函数无参,但是声明了参数列表,那么调用时,小括号,可加可不加
def f7() = "dalang7"
println(f7())
def f8 = "dalang"
//println(f8())
println(f8)
//(9)如果不关心名称,只关心逻辑处理,那么函数名(def)可以省略
def f9 = (x: String) => {
println("wusong")
}
def f10(f: String => Unit) = {
f("")
}
f10(f9)
println(f10((x: String) => {
println("wusong")
}))
}
}
(二)函数高级
1、高阶函数
- 在 Scala 中,函数是一等公民。怎么体现的呢?
- 对于一个函数我们可以:定义函数、调用函数
package net.cch.scala.day04
/**
* 功能: 高级函数
* 作者: 陈春宏
* 时间: 2022/6/20 11:17
*/
object TestFunction4 {
def main(args: Array[String]): Unit = {
// 调用函数
foo()
}
// 定义函数
def foo():Unit = {
println("foo ...")
}
}
(1)函数可以作为值进行传递
package net.cch.scala.day04
/**
* 功能: 函数作为值传递
* 作者: 陈春宏
* 时间: 2022/6/20 11:20
*/
object TestFunction5 {
def main(args: Array[String]): Unit = {
//(1)调用 foo 函数,把返回值给变量 f
//val f = foo
val f = foo()
println(f)
val f1 = foo _
foo()
f1()
//(3)如果明确变量类型,那么不使用下划线也可以将函数作为整体传递给变量
var f2:()=>Int = foo
}
def foo():Int = {
println("foo...")
1
}
}
(2)函数可以作为参数进行传递
package net.cch.scala.day04
/**
* 功能: 函数作为参数传递
* 作者: 陈春宏
* 时间: 2022/6/20 11:23
*/
object TestFunction6 {
def main(args: Array[String]): Unit = {
// (1)定义一个函数,函数参数还是一个函数签名;f 表示函数名称;(Int,Int) 表示输入两个 Int 参数;Int 表示函数返回值
def f1(f: (Int, Int) => Int): Int = {
f(2, 4)
}
// (2)定义一个函数,参数和返回值类型和 f1 的输入参数一致
def add(a: Int, b: Int): Int = a + b
// (3)将 add 函数作为参数传递给 f1 函数,如果能够推断出来不是调用,可以省略
println(f1(add))
println(f1(add _))
//可以传递匿名函数
}
}
(3)函数可以作为函数返回值返回
package net.cch.scala.day04
/**
* 功能: 函数作为返回值返回
* 作者: 陈春宏
* 时间: 2022/6/20 11:25
*/
object TestFunction7 {
def main(args: Array[String]): Unit = {
def f1() = {
def f2() = {
}
f2 _
}
val f = f1()
// 因为 f1 函数的返回值依然为函数,所以可以变量 f 可以作为函数继续调用
f()
// 上面的代码可以简化为
f1()()
}
}
2、匿名函数
(1)说明
- 没有名字的函数就是匿名函数。
(x:Int)=>{函数体}
- x:表示输入参数类型;Int:表示输入参数类型;函数体:表示具体代码逻辑
(2)实操
-
需求一:传递的函数有一个参数
-
传递匿名函数至简原则:
(1)参数的类型可以省略,会根据形参进行自动的推导
(2)类型省略之后,发现只有一个参数,则圆括号可以省略;其他情况:没有参数和参
数超过 1 的永远不能省略圆括号。
(3)匿名函数如果只有一行,则大括号也可以省略
(4)如果参数只出现一次,则参数省略且后面参数可以用_代替
package net.cch.scala.day04
/**
* 功能: 匿名函数
* 作者: 陈春宏
* 时间: 2022/6/20 16:54
*/
object TestAnonymousFunction {
def main(args: Array[String]): Unit = {
//(1)定义一个函数:参数包含数据和逻辑函数
def operation(arr:Array[Int],op:Int =>Int) = {
for(elem <- arr) yield op (elem)
}
// (2)定义逻辑函数
def op(ele: Int): Int = {
ele + 1
}
// (3)标准函数调用
val arr = operation(Array(1, 2, 3, 4), op)
println(arr.mkString(","))
// (4)采用匿名函数
val arr1 = operation(Array(1, 2, 3, 4), (ele: Int) => {
ele + 1
})
println(arr1.mkString(","))
// (4.1)参数的类型可以省略,会根据形参进行自动的推导;
val arr2 = operation(Array(1, 2, 3, 4), (ele) => {
ele + 1
})
println(arr2.mkString(","))
// (4.2)类型省略之后,发现只有一个参数,则圆括号可以省略;其他情况:没有参数和参数超过 1 的永远不能省略圆括号。
val arr3 = operation(Array(1, 2, 3, 4), ele => {
ele + 1
})
println(arr3.mkString(","))
// (4.3) 匿名函数如果只有一行,则大括号也可以省略
val arr4 = operation(Array(1, 2, 3, 4), ele => ele + 1)
println(arr4.mkString(","))
//(4.4)如果参数只出现一次,则参数省略且后面参数可以用_代替
val arr5 = operation(Array(1, 2, 3, 4), _ + 1)
println(arr5.mkString(","))
}
}
- 需求 2:传递的函数有两个参数
package net.cch.scala.day04
/**
* 功能: 匿名函数
* 作者: 陈春宏
* 时间: 2022/6/20 16:54
*/
object TestAnonymousFunction01 {
def main(args: Array[String]): Unit = {
def calculator(a: Int, b: Int, op: (Int, Int) => Int): Int = {
op(a, b)
}
// (1)标准版
println(calculator(2, 3, (x: Int, y: Int) => {
x + y
}))
// (2)如果只有一行,则大括号也可以省略
println(calculator(2, 3, (x: Int, y: Int) => x + y))
// (3)参数的类型可以省略,会根据形参进行自动的推导;
println(calculator(2, 3, (x, y) => x + y))
// (4)如果参数只出现一次,则参数省略且后面参数可以用_代替
println(calculator(2, 3, _ + _))
}
}
3、高阶函数案例
- 需求:模拟 Map 映射、Filter 过滤、Reduce 聚合
package net.cch.scala.day04
import scala.collection.mutable.ArrayBuffer
/**
* 功能: 高阶函数案例
* 作者: 陈春宏
* 时间: 2022/6/20 16:54
*/
object TestAnonymousFunction02 {
def main(args: Array[String]): Unit = {
// (1) map 映射
def map(arr: Array[Int], op: Int => Int) = {
for (elem <- arr) yield op(elem)
}
val arr = map(Array(1, 2, 3, 4), (x: Int) => {
x * x
})
println(arr.mkString(","))
// (2)filter 过滤。有参数,且参数再后面只使用一次,则参数省略且后面参数用_表示
def filter(arr:Array[Int],op:Int =>Boolean) ={
var arr1:ArrayBuffer[Int] = ArrayBuffer[Int]()
for(elem <- arr if op(elem)){
arr1.append(elem)
}
arr1.toArray
}
var arr1 = filter(Array(1, 2, 3, 4), _ % 2 == 1)
println(arr1.mkString(","))
// (3)reduce 聚合。有多个参数,且每个参数再后面只使用一次,则参数省略且后面参数用_表示,第 n 个_代表第 n 个参数
def reduce(arr: Array[Int], op: (Int, Int) => Int) = {
var init: Int = arr(0)
for (elem <- 1 until arr.length) {
init = op(init, elem)
}
init
}
//val arr2 = reduce(Array(1, 2, 3, 4), (x, y) => x * y)
val arr2 = reduce(Array(1, 2, 3, 4), _ * _)
println(arr2)
}
}
4、函数柯里化&闭包
- 闭包:函数式编程的标配
(1)说明
- 闭包:如果一个函数,访问到了它的外部(局部)变量的值,那么这个函数和他所处的
环境,称为闭包 - 函数柯里化:把一个参数列表的多个参数,变成多个参数列表。
(2)案例
package net.cch.scala.day04
/**
* 功能: 函数闭包
* 作者: 陈春宏
* 时间: 2022/6/20 17:08
*/
object TestFunctionClosure {
def main(args: Array[String]): Unit = {
def f1()={
var a:Int = 10
def f2(b:Int)={
a + b
}
f2 _
}
// 在调用时,f1 函数执行完毕后,局部变量 a 应该随着栈空间释放掉
val f = f1()
// 但是在此处,变量 a 其实并没有释放,而是包含在了 f2 函数的内部,形成了闭合的效果
println(f(3))
println(f1()(3))
// 函数柯里化,其实就是将复杂的参数逻辑变得简单化,函数柯里化一定存在闭包
def f3()(b:Int)={
a + b
}
println(f3()(3))
}
}
5、递归
(1)说明
- 一个函数/方法在函数/方法体内又调用了本身,我们称之为递归调用
(2)案例
package net.cch.scala.day04
/**
* 功能: 递归
* 作者: 陈春宏
* 时间: 2022/6/20 17:13
*/
object TestRecursion {
def main(args: Array[String]): Unit = {
// 阶乘
// 递归算法
// 1) 方法调用自身
// 2) 方法必须要有跳出的逻辑
// 3) 方法调用自身时,传递的参数应该有规律
// 4) scala 中的递归必须声明函数返回值类型
println(test(5))
}
def test(i : Int) : Int = {
if (i == 1) {
1
} else {
i * test(i - 1)
}
}
}
6、控制抽象
(1)值调用:把计算后的值传递过去
package net.cch.scala.day04
/**
* 功能: 控制抽象
* 作者: 陈春宏
* 时间: 2022/6/20
*/
object ControlAbstraction {
def main(args: Array[String]): Unit = {
def f = ()=>{
println("f...")
10
}
foo(f())
}
def foo(a: Int):Unit = {
println(a)
println(a)
}
}
(2)名调用:把代码传递过去
package net.cch.scala.day04
/**
* 功能: 名调用
* 作者: 陈春宏
* 时间: 2022/6/20 17:49
*/
object TestControl {
def main(args: Array[String]): Unit = {
def f = ()=>{
println("f...")
10
}
foo(f())
}
//def foo(a: Int):Unit = {
def foo(a: =>Int):Unit = {//注意这里变量 a 没有小括号了
println(a)
println(a)
}
}
(3)案例
package net.cch.scala.day04
/**
* 功能:
* 作者: 陈春宏
* 时间: 2022/6/20 17:51
*/
object TestFunction8 {
def main(args: Array[String]): Unit = {
// (1)传递代码块
foo({
println("aaa")
})
// (2)小括号可以省略
foo{
println("aaa")
}
def foo(a: =>Unit):Unit = {
println(a)
println(a)
}
}
}
- 自定义一个while循环
package net.cch.scala.day04
/**
* 功能: 抽象控制
* 作者: 陈春宏
* 时间: 2022/6/20 17:52
*/
object TestFunction9 {
def main(args: Array[String]): Unit = {
var i:Int = 1
myWhile(i <= 10){
println(i)
i +=1
}
}
def myWhile(condition: =>Boolean)(op: =>Unit):Unit={
if (condition){
op
myWhile(condition)(op)
}
}
}
7、惰性加载
(1)说明
- 当函数返回值被声明为 lazy 时,函数的执行将被推迟,直到我们首次对此取值,该函
数才会执行。这种函数我们称之为惰性函数。
(2)案例
package net.cch.scala.day04
/**
* 功能: 惰性加载
* 作者: 陈春宏
* 时间: 2022/6/20
*/
object TestFunction01 {
def main(args: Array[String]): Unit = {
lazy val res = sum(10, 30)
println("----------------")
println("res=" + res)
}
def sum(n1: Int, n2: Int): Int = {
println("sum 被执行。。。")
return n1 + n2
}
}
- 注意:lazy 不能修饰 var 类型的变量