-
面向对象编程
解决问题,分解对象,行为,属性,然后通过对象的关系以及行为的调用来解决问题
对象:用户
行为:登录、连击JDBC、读取数据库
属性:用户名、密码
Scala语言是一个完全面向对象编程语言,万物皆对象
对象的本质:对数据和行为的一个封装 -
函数式编程
解决问题时,酱问题分解成一个一个的步骤,将每个步骤进行封装(函数),通过调用这些封装好的步骤,解决问题。例如:请求->用户名、密码->连接JDBC->读取数据库
Scala语言是一个完全函数式编程语言,万物皆函数。
函数的本质:函数可以当做一个值进行传递 -
在Scala中函数式编程和面向对象编程完美融合在一起。
函数基础
基本语法
// (1)函数定义
def f(arg: String): Unit = {
println(arg)
}
// (2)函数调用
// 函数名(参数)
f("hello world")
函数和方法的区别
- 核心概念
为完成某一功能的程序语句的几个,称为函数。
类中的函数称之为方法。 - 区别
Scala语言可以在任何的语法结构中声明任何的语法
函数没有重载和重写的概念;方法可以进行重载和重写
Scala中函数可以嵌套定义
package com.gm.chapter04
/**
* @Author: Gm
* @Date: 2021/6/17 14:14
*/
object Test01_Function {
//方法可以进行重载和重写,程序可以执行
def main(): Unit = {
}
def main(args: Array[String]): Unit = {
//定义函数
def function(arg: String):Unit = {
println(arg)
}
//调用函数
//函数名(参数)
function("gaomin")
//Scala语言可以在任何的语法结构中声明任何的语法
import java.util.Date
new Date()
//函数没有重载和重写的概念,程序报错
// def function() :Unit = {
// println("chongzai")
// }
//Scala中函数可以嵌套定义
def function2(): Unit = {
def function3(): Unit = {
println("Scala中函数可以嵌套定义")
}
}
}
}
函数定义
函数定义
- 无参,无返回值
- 无参,有返回值
- 有参,无返回值
- 有参,有返回值
- 多参,无返回值
- 多参,有返回值
package com.gm.chapter04
/**
* @Author: Gm
* @Date: 2021/6/17 14:26
*/
object Test02_FunctionDefined {
def main(args: Array[String]): Unit = {
//函数1:无参,无返回值
def test1(): Unit = {
println("无参,无返回值")
}
test1()
//无参,有返回值
def test2(): String = {
return "无参,有返回值"
}
println(test2())
//有参,无返回值
def test3(s: String): Unit = {
println(s)
}
test3("有参,无返回值")
//有参,有返回值
def test4(s: String): String = {
return s
}
println(test4("有参,有返回值"))
//多参,无返回值
def test5(s: String, a: Int): Unit = {
println(s"$s -- $a")
}
test5("gaomin",22)
//多参,有返回值
def test6(s: String,a: Int): String = {
return s"$s -- $a"
}
println(test6("gaomin1",34))
}
}
函数参数
- 可变参数
- 如果参数列表中存在多个参数,那么可变参数一半放置在最后
- 参数默认值,一半有默认值的参数放置在参数列表的后面
- 带名参数
package com.gm.chapter04
/**
* @Author: Gm
* @Date: 2021/6/17 14:36
*/
object Test03_FunctionParameter {
def main(args: Array[String]): Unit = {
//可变参数
def test1(s: String*): Unit = {
println(s)
}
test1("gaomin","Scala") //WrappedArray(gaomin, Scala)
test1() //List()
//如果参数列表中存在多个参数,那么可变参数一般防止在最后
def test2(name: String , s: String*): Unit ={
println(s"$name -- $s")
}
test2("gaomin","wudi","dage")
//参数默认值
def test3(name: String,age:Int = 30): Unit ={
println(s"$name -- $age")
}
// 如果参数传递了值,那么会覆盖默认值
test3("gaomin", 20)
// 如果参数有默认值,在调用的时候,可以省略这个参数
test3("gao")
//一般情况下,将有默认值的参数放置在参数列表的后面
def test4(sex: String = "male",name: String): Unit ={
println(s"$name,$sex")
}
//Scala函数中参数传递是,从左到右
// test4("gaomin")
//带名参数
test4(name = "gaomin")
}
}
函数至简原则(重点学习):能省则省
- return可以省略,Scala会使用函数体的最后一行代码作为返回值
- 如果函数体只有一行代码,可以省略花括号
- 返回值类型如果能够推断出来,那么可以省略(:和返回值类型一起省略)
- 如果有return,则不能省略返回值类型,必须指定
- 如果函数明确声明unit,那么即使函数体中使用return关键字也不起作用
- Scala如果期望是无返回值类型,可以省略等号
- 如果函数无参,但是声明了参数列表,那么调用时,小括号,可加不可加
- 如果函数没有参数列表,那么小括号可以省略,调用时小括号必须省略
- 如果不关心名称,只关心逻辑处理,那么函数名(def)可以省略
package com.gm.chapter04
/**
* @Author: Gm
* @Date: 2021/6/17 14:50
*/
object Test04_FunctionSimplify {
def main(args: Array[String]): Unit = {
//初始函数的定义
def sayHi(name: String): String = {
return name
}
//return可以省略,Scala会使用函数体的最后一行代码作为返回值
def sayHi1(name: String): String = {
name
}
//如果函数体只有 一行代码可以省略花括号
def sayHi2(name: String): String = name
//如果返回值类型能够推断出来,那么可以省略(:和返回值类型一起省略)
def sayHi3(name: String)= name+1
//如果有return,则不能省略返回值类型,必须指明
def sayHi4(name: String): String = return name+1
//如果函数明确声明为Unit,那么即使函数体中使用return关键字也不起作用
def sayHi5(name: String): Unit = return name+1
val gaomin: Unit = sayHi5("gaomin")
println(gaomin)
//如果Scala期望是无返回值类型,可以省略等号,但是要加上花括号
def sayHi6(name: String) {
println(name)
println("ggg")
}
//如果函数无参,但是声明了参数列表,那么调用时,小括号可加可不可加
def sayHi7() = println("hello")
sayHi7
sayHi7()
//如果函数没有参数列表,那么小括号可以省略,调用时小括号必须省略
def sayHi8 = println("hello")
sayHi8
//如果不关心名称,只关心逻辑处理,那么函数名(def)可以省略
val function: String => String = (name: String) => name+1
}
}
函数高阶
高阶函数
- 函数可以作为值进行传递
- 函数可以作为参数进行传递
- 函数可以作为函数返回值返回
package com.gm.chapter04
/**
* @Author: Gm
* @Date: 2021/6/18 8:55
*/
object Test06_FunctionAdvance {
def main(args: Array[String]): Unit = {
//定义函数
def sayHi(name: String): String = {
name
}
val gaomin: String = sayHi("gaomin")
//1.函数可以作为值进行传递
val hi1 = sayHi _ //" _"表示的是这个函数本身
println(hi1) //com.gm.chapter03.Test06_FunctionAdvance$$$Lambda$1/1915910607@4563e9ab
val hi2: String => String = sayHi //明确返回值类型也能表示自身
println(hi2) //com.gm.chapter03.Test06_FunctionAdvance$$$Lambda$6/290658609@5e025e70
val hi3: String => String = (name: String) => name
println(hi3) //com.gm.chapter03.Test06_FunctionAdvance$$$Lambda$7/532445947@45c8e616
//2.函数可以作为参数进行传递
def sum(x: Int, y: Int): Int = {
x + y
}
def func1(x: Int, y: Int, function: (Int, Int) => Int): Int = {
function(x , y)
}
func1(1, 1, sum)
func1(1, 1, _ - _)
func1(1, 1, (x: Int, y: Int) => y * 2 - 3 * x)
func1(1, 1, (x, y) => y * 2 - 3 * x)
func1(1, 1, -3 * _ + _ * 2)
//3.函数可以作为函数返回值返回
def sayHello1(name: String, age: Int): Unit = {
println(s"欢迎$age 岁的$name 来玩")
}
def sayHello2(name: String):Int => Unit = {
def addAge(age: Int): Unit = {
println(s"欢迎$age 岁的$name 来玩")
}
addAge
}
val gaomin1 = sayHello2("gaomin1")
gaomin1(15)
}
}
匿名函数
说明
- 没有名字的函数就是匿名函数。
- (x:Int)=>{函数体}:x:表示输入参数类型;Int:表示输入参数类型;函数体:表示具体代码逻辑
传递匿名函数至简原则
- 参数的类型可以省略,会根据形参进行自动的推导
- 类型省略之后,发现只有一个参数,则圆括号可以省略;其他的情况:没有参数和参数超过1的永远不能省略圆括号。
- 匿名函数如果只有一行,则大括号也可以省略
- 如果参数只出现一次,则参数省略且后面参数可以用_代替
package com.gm.chapter04
/**
* @Author: Gm
* @Date: 2021/6/17 15:25
*/
object Test05_LambdaSimplify {
def main(args: Array[String]): Unit = {
//定义一个两个数相加的函数
def sumXY(x: Int, y: Int): Int = {
x + y
}
//匿名函数的写法
val function: (Int, Int) => Int = (x: Int, y: Int) => x + y
//参数的类型可以省略,会根据形参进行自动的推导
val function1: (Int, Int) => Int = (x, y) => x + y
//类型省略之后,发现只有一个参数,则圆括号可以省略;其他情况:没有参数和参数超过1的永远不能省略
val function2: String => String = { name =>
println("gaomin")
name
}
//如果匿名函数只有一行,则大括号也可以省略
val function3: String => String = name => name
//如果参数值出现一次,并且参数出现的顺序是按照参数列表的顺序
//则参数省略且后面参数可以用_代替
val function4: (Int, Int) => Int = _ - _
// val function5: String => String = _ //报错是因为_的使用方式太多了,无法识别
val function5: String => String = _+"" //限定成String就能识别了
//_的使用方式
/*
* 引用时表示包下的所有对象
* 表示初始值
* 匿名函数中的参数化简
* */
}
}
函数柯里化&闭包
说明
- 闭包:如果一个函数,访问到了它的外部(局部)变量的值,那么这个函数和他所处的环境,称为闭包。
- 函数柯里化:把一个参数列表的多个参数,变成多个参数列表
package com.gm.chapter04
/**
* @Author: Gm
* @Date: 2021/6/18 9:31
*/
object Test07_ProblemsClosure {
def main(args: Array[String]): Unit = {
//定义一个常规的函数
//泛用性比较强,适用性较差
def sumXY(x: Int,y: Int): Int = {
x + y
}
//适用性更强了,用起来就更加方便
def sumByFour(y: Int): Int = {
4 + y
}
def sumByFive(y: Int): Int = {
5 + y
}
//适用性变强了,泛用性就变差了
//需要一个折中的方法,能够即使的创造出对应的函数
def sumByX(x: Int): Int => Int ={
def sum(y: Int): Int= {
x + y
}
sum
}
val i = sumByX(4)(5)
println(i)
//需求1. 写一个函数,形参是(Char,Int,String)
//如果传入的参数是('0',0,"")返回false,否则返回true
def check(x: Char,y: Int,z: String): Boolean ={
if (x == '0' && y == 0 && z == "") false else true
}
println(check('0',0,""))
println(check('0',1,""))
def check2(x: Char,y: Int,z: String): Boolean = !(x == '0' && y == 0 && z == "")
def func1:(Char,Int,String) => Boolean = (x: Char,y: Int,z: String)=> x != '0' || y != 0 || z != ""
def func2:(Char,Int,String) => Boolean = (x,y,z)=> x != '0' || y != 0 || z != ""
def func3:(Char,Int,String) => Boolean = _ != '0' || _ != 0 || _ != ""
// (Char,Int,String) => _ != '0' || _ != 0 || _ != ""
//需求2. 写一个函数 形参是(Char)(Int)(String)
//如果传入的参数是('0')(0)("")返回false,否则返回true
def check1(x: Char)={
def c1(y: Int) ={
def c2(z: String) = {
x != '0' || y != 0 || z != ""
}
c2 _
}
c1 _
}
def check3(x: Char):Int => String => Boolean = y => z => x == '0' || y == 0 || z == ""
def c3(x: Char)(y: Int)(z: String): Boolean = x == '0' || y == 0 || z == ""
// println(check3('0')(0)(""))
}
}
递归
一个函数/方法在函数/方法体内又调用了本身,我们称之为递归调用
package com.gm.chapter04
import scala.annotation.tailrec
/**
* @Author: Gm
* @Date: 2021/6/18 11:25
*/
object Test08_Recursion {
def main(args: Array[String]): Unit = {
//实现一个阶乘
def rec1(n: Int): Long = {
var res: Long = 1
for (i <- 1 to n) {
res *= i
}
res
}
println(rec1(5))
//使用递归完成阶乘
//1.调用自身代码
//2.有结束递归的条件
def rec2(n: Int): Long = {
if (n == 1) 1 else rec2(n - 1) * n
}
println(rec2(5))
//尾递归优化
def rec3(n: Int): Long = {
@tailrec
def rec(m: Int, res: Long): Long = {
if (m == 1) res else rec(m - 1, res * m)
}
rec(n, res = 1)
}
println(rec3(5))
}
}
抽象控制
package com.gm.chapter04
/**
* @Author: Gm
* @Date: 2021/6/18 14:32
*/
object Test09_ControlAbstract {
def main(args: Array[String]): Unit = {
//值调用
def sayHi(name: String): String = {
println("sayHi")
println(name)
s"hi $name"
}
//值调用不是调用函数
println(sayHi({
println("值调用")
"zhangsan" + " lisi"
}))
println("===============================")
//名调用
def sayHi1(name: => String): String = {
println("sayHi")
println(name)
s"hi $name"
}
println(sayHi1({
println("名调用")
"函数"
}))
}
}
自定义一个While循环
package com.gm.chapter04
/**
* @Author: Gm
* @Date: 2021/6/18 14:39
*/
object MyWhile {
def main(args: Array[String]): Unit = {
//使用系统提供的while
var n = 0
while (n < 10) ({
println(n)
n += 1
})
def myWhile(condition: => Boolean)(op: => Unit): Unit = {
if (condition) {
op
myWhile(condition)(op)
}
}
n = 0
myWhile(n < 10) {
println(n)
n += 1
}
}
}
惰性函数
- 当函数返回值被声明为lazy时,函数的执行将被推迟,知道我们首次对此取值,该函数才会执行。
package com.gm.chapter04
/**
* @Author: Gm
* @Date: 2021/6/18 14:50
*/
object Test10_LazyFunction {
def main(args: Array[String]): Unit = {
def sum(x: Int,y: Int): Int = {
println("函数调用")
x + y
}
//惰性函数
//当函数返回值被声明为lazy时,函数的执行将被推迟,知道我们首次对此取值,该函数才会执行。
lazy val n1 = sum(10 ,30)
println("==============")
println(n1)
}
}