最近由于要用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循环中的表达式:映射
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
val i = 3.14
val i = true
val i = 'A'
val i = "Hello"
在非函数式编程语言里,函数的定义包含了“函数类型”和“值”两种层面的内容。
但是,在函数式编程中,函数是“头等公民”,可以像任何其他数据类型一样被传递和操作,也就是说,
函数的使用方式和其他数据类型的使用方式完全一致了。这时,我们就可以像定义变量那样去定义一个函数,
由此导致的结果是,函数也会和其他变量一样,开始有“值”。就像变量的“类型”和“值”是分开的两个概念一样,
函数式编程中,函数的“类型”和“值”也成为两个分开的概念,函数的“值”,就是“函数字面量”。
定义函数最常用的式子:
def counter(value: Int): Int = { value += 1}
函数的“类型”:
(Int) => Int
注:有多个参数时(不同参数之间用逗号隔开),圆括号才是必须的,函数的类型也可以写成: Int => Int
只要把函数定义中的类型声明部分去除,剩下的就是函数的“值”:
b.Scala定义函数的方式:
声明一个变量:
类似的,定义一个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}
val myFunc = plusStep(3)
println(myFunc(10))
}
}
step是一个自由变量,它的值只有在运行的时候才能确定,num的类型是确定的,num的值只有在调用的时候才被赋值。这样的函数,被称为“闭包”,它反映了一个从开放到封闭的过程
一般的函数:
闭包:
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)
}
让一个函数作为另一个函数的参数:
def sum(f: Int => Int, a: Int, b: Int): Int ={
if(a > b) 0 else f(a) + sum(f, a+1, b)
}
def self(x: Int): Int = x
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/
评论