Scala 编程基础笔记

用户头像
郑可夫斯基
关注
发布于: 2020 年 10 月 12 日
Scala编程基础笔记

最近由于要用spark作为开发工具,为了深入了解Spark,我在狂补Scala的知识,下面是我的学习笔记



1.模式匹配

a.简单匹配之match语句



val colorNum = 1
val colorStr = colorNum match{
case 1 => "red"
case 2 => "green"
case 3 => "yellow"
case _ => "Not Allowed"
}
println(colorStr)



b.模式匹配的case语句中,还可以使用变量



val colorNum = 4
val colorStr = colorNum match{
case 1 => "red"
case 2 => "green"
case 3 => "yellow"
case unexpected => unexpected + " is Not Allowed"
}
println(colorStr)



c.按照类型进行匹配



for (elem <- List(9,3.18,"Spark","Hadoop",'Hello)){
val type_str = elem match{
case i:Int => i + " is an int value."
case d:Double => d + " is a double value."
case "Spark" => "Spark is found."
case s:String => s + " is a string value."
case _ => "This is an unexpected value."
}
println(type_str)
}



d.在"=>"左边增加条件表达式



for (elem <- List(1,2,3,4)){
elem match {
case _ if (elem %2 == 0) => println(elem + " is even.")
case _ => println(elem + " is odd.")
}
}



e.for循环中的表达式:映射



for ((k,v) <- 映射) 语句块



val university = Map("NJU" -> "Nanjing University", "THU" -> "Tsinghua University","PKU"->"Peking University")
for ((k,v) <- university) printf("Code is : %s and name is: %s\n",k,v)



f.case类的匹配:case类是一种特殊的类,它们经过优化以被用于模式匹配



case class Car(brand:String,price:Int)
val Car01 = new Car("BYD",90000)
val Car02 = new Car("BMW",100000)
val Car03 = new Car("BNZ",110000)
for (car <- List(Car01,Car02,Car03)){
car match{
case Car("BYD",90000) => println("Hello,BYD!")
case Car("BMW",100000) => println("Hello,BMW!")
case Car(brand,price) => println("Brand: " + brand + ",Price: "+price)
}
}



g.待了解: Option类型,Option类型的子类Some,Any类型,getOrElse方法



val books = Map("hadoop" -> 5,"spark" -> 10,"hbase" -> 15)
books.get("hadoop")
books.get("hive")
val sales = books.get("hive")
sales.getOrElse("No Such Book")
println(sales.getOrElse("No Such Book"))
books.get("hive").foreach(println)



运行结果:



2.Scala函数



a.函数字面量

字面量包括整数字面量、浮点数字面量、布尔型字面量、字符字面量、字符串字面量、符号字面量、函数字面量和元组字面量



val i = 123 //123就是整数字面量
val i = 3.14 //3.14就是浮点数字面量
val i = true //true就是布尔型字面量
val i = 'A' //'A'就是字符字面量
val i = "Hello" //"Hello"就是字符串字面量



在非函数式编程语言里,函数的定义包含了“函数类型”和“值”两种层面的内容。

但是,在函数式编程中,函数是“头等公民”,可以像任何其他数据类型一样被传递和操作,也就是说,

函数的使用方式和其他数据类型的使用方式完全一致了。这时,我们就可以像定义变量那样去定义一个函数,

由此导致的结果是,函数也会和其他变量一样,开始有“值”。就像变量的“类型”和“值”是分开的两个概念一样,

函数式编程中,函数的“类型”和“值”也成为两个分开的概念,函数的“值”,就是“函数字面量”。



定义函数最常用的式子:

def counter(value: Int): Int = { value += 1}



函数的“类型”:

(Int) => Int



注:有多个参数时(不同参数之间用逗号隔开),圆括号才是必须的,函数的类型也可以写成: Int => Int



只要把函数定义中的类型声明部分去除,剩下的就是函数的“值”:

(value) => {value += 1} //只有一条语句时,大括号可以省略



b.Scala定义函数的方式:



声明一个变量:

val num: Int = 5



类似的,定义一个Scala函数:

val counter: (Int) => Int = { (value) => value += 1 }

或简写为:

val counter: Int => Int = { (value) => value += 1 }



定义一个函数,只要在某个需要声明函数的地方声明一个函数类型,在调用的时候传一个对应的函数字面量即可,和使用普通变量一模一样



c.匿名函数、Lambda表达式与闭包

不需要给函数命名时就用匿名函数:

(num: Int) => num * 2



上面这种匿名函数的定义形式,我们经常称为“Lambda表达式”

Lambda表达式的定义公式:

(参数) => 表达式 //如果参数只有一个,参数的圆括号可以省略



可以直接把匿名函数存放到变量中



val NumFunc:Int => Int = (num) => num * 2
println(NumFunc(3))



"Int => Int",一般可以去掉,因为Scala解释器可以做自动类型推断

*此时需要给num加类型声明



val NumFunc = (num:Int) => num * 2
println(NumFunc(3))



d.闭包



object MyTest{
def main(args: Array[String]): Unit={
def plusStep(step: Int) = (num: Int) => {num + step}
//给step赋值
val myFunc = plusStep(3)
//调用myFunc函数
println(myFunc(10))
}
}



step是一个自由变量,它的值只有在运行的时候才能确定,num的类型是确定的,num的值只有在调用的时候才被赋值。这样的函数,被称为“闭包”,它反映了一个从开放到封闭的过程



一般的函数:

val addMore=(x:Int)=>x>0

闭包:

val addMore=(x:Int)=>x+more



more并没有在函数中定义,是一个函数外部的变量,必须在函数外部给出more的值



完整代码:

var more = 1
val addMore=(x:Int)=>x+more
println(addMore(10))



让函数addMore中的more变量绑定了具体的值1,不再是“自由变量”,而是被绑定具体的值了,或者说“被关闭”了,这也是为什么我们说这样一个函数叫做“闭包”,它反映了一个从开放到封闭的过程。



动态修改变量more,每次addMore函数被调用时都会创建一个新闭包



var more = 1
val addMore=(x:Int)=>x+more
println(addMore(10))
more = 2
println(addMore(10))
more = 3
println(addMore(10))



运行结果:

11

12

13

[Finished in 5.7s]



e.高阶函数

一个接受其他函数作为参数或者返回一个函数的函数就是高阶函数



举例,有一个函数对给定两个数区间中的所有整数求和:

[1,3] => 1 + 2 + 3



普通写法:

def sumFunc(a:Int,b:Int):Int = {
if(a > b) 0 else a + sumFunc(a + 1,b)
}



让一个函数作为另一个函数的参数:

//定义了一个新的函数sum,以函数f为参数
def sum(f: Int => Int, a: Int, b: Int): Int ={
if(a > b) 0 else f(a) + sum(f, a+1, b)
}
//定义了一个新的函数self,该函数的输入是一个整数x,然后直接输出x自身
def self(x: Int): Int = x
//重新定义sumInts函数
def sumFunc(a: Int, b: Int): Int = sum(self, a, b)



函数sum的类型: (Int=>Int, Int, Int) => Int



函数sum是一个接受函数参数的函数,因此,是一个高阶函数。



3.占位语法

使用下划线作为一个或多个参数的占位符,只要每个参数在函数字面量内仅出现一次



val numList = List(-3, -5, 1, 6, 9)
numList.filter(x => x > 0 )
numList.filter(_ > 0)

"x => x>0" 和 "_ > 0" 等价



当采用下划线的表示方法时,对于列表numList中的每个元素,都会依次传入用来替换下划线,比如,首先传入-3,然后判断-3>0是否成立,如果成立,就把该值放入结果集合,如果不成立,则舍弃,接着再传入-5,然后判断-5>0是否成立,依此类推。



参考教程: http://dblab.xmu.edu.cn/blog/spark/

用户头像

郑可夫斯基

关注

Stay hungry ,Stay foolish. 2020.02.15 加入

【微信公众号】背包客Revolution

评论

发布
暂无评论
Scala编程基础笔记