<!– Scala,一门「特立独行」的语言!–>
入门 Spark 的路上很难不接触 Scala。Scala 仿佛是为 java 提供了很多『相似函数式编程』的语法糖,这里记录一下这个语言独特的中央分享给读者敌人们。
参考资料次要有:
- 曹洁 . Spark 大数据分析技术(Scala 版)[M]. 北京航空航天大学出版社, 2021. ISBN:9787512433854
- 陈欢 , 林世飞 . Spark 最佳实际 [M]. 人民邮电出版社, 2016. ISBN:9787115422286
Scala 根本思维与注意事项
Sacla 即 Scalable Language,正如其名,是一门可伸缩的编程语言:
- 基于 java 的虚拟机(Scala 会被编译成 JVM 字节码)
- 然而既能够当脚本应用,又能够结构大型零碎
- 是动态语言,然而能够像动静语言那样反对交互式编程
- 面型对象:每一个值都是对象,每一次运算都是一次办法调用
- 函数式编程:所有函数都是对象,函数是“一等公民”
- Scala 中简直一切都是表达式
scala
是解释器,scalac
是编译器;能够间接 scala test.scala
,也能够 scalac test.scala & scala test
(先把源码编译为字节码,再把字节码放到虚拟机中解释运行)。还可用输出 scala
进入替换编程界面。
所以要留神的是,须要先装置 JDK,并且设置好环境变量 JAVA_HOME
。此外,更加重要的是,Scala 小版本兼容:2.12.x
与 2.13.x
这两者不兼容,2.12.10
与 2.12.11
才兼容。
最根本的语法示例
类型的申明、控制结构(for、模式匹配、case)
// 变量
val two: Int = 1 + 1
var one: Int = 1
var one: String = 'one'
// 函数
def addOne(x: Int): Int = x + 1
def add(x: Int, y: Int): Int = {x + y}
// 局部控制结构
var filename =
if (!args.isEmpty) args(0)
else "default.txt"
for (i <- 1 to 4)
println("iteration" + i)
1 to 4
是 [1,2,3,4]
,而 i until 4
是 [1,2,3]
。
对于 for
还有一些奇技淫巧。
// 多个区间
for (a <- 1 to 2; b <- 1 to 2) {println("a:" + a + ", b:" + b)
}
// 后果
a: 1, b: 1
a: 1, b: 2
a: 2, b: 1
a: 2, b: 2
// 过滤器
val list1 = List(3, 5, 2, 1, 7)
for (x <- list1 if x % 2 == 1) print(" " + x)
// 3 5 1 7
对于模式匹配,则有更多奇技淫巧。这里我间接参考:scala 中 case 的用法
// 一. 简略匹配,值匹配:val bools = List(true, false)
for (bool <- bools) {
bool match {case true => println("heads")
case false => println("tails")
case _ => println("something other than heads or tails (yikes!)")
}
}
import scala.util.Random
val randomInt = new Random().nextInt(10)
randomInt match {case 7 => println("lucky seven!")
case otherNumber => println("boo, got boring ol' " + otherNumber)
}
// 二. 类型匹配
val sundries = List(23, "Hello", 8.5, 'q')
for (sundry <- sundries) {
sundry match {case i: Int => println("got an Integer:" + i)
case s: String => println("got a String:" + s)
case f: Double => println("got a Double:" + f)
case other => println("got something else:" + other)
}
}
// 三 依据程序匹配
val willWork = List(1, 3, 23, 90)
val willNotWork = List(4, 18, 52)
val empty = List()
for (l <- List(willWork, willNotWork, empty)) {
l match {case List(_, 3, _, _) => println("Four elements, with the 2nd being'3'.")
case List(_*) => println("Any other list with 0 or more elements.")
}
}
// 四 case 外面用 guard 的数组匹配
val tupA = ("Good", "Morning!")
val tupB = ("Guten", "Tag!")
for (tup <- List(tupA, tupB)) {
tup match {case (thingOne, thingTwo) if thingOne == "Good" =>
println("A two-tuple starting with'Good'.")
case (thingOne, thingTwo) =>println("This has two things:" + thingOne + "and" + thingTwo)
}
}
// 五 对象深度匹配
case class Person(name: String, age: Int)
val alice = new Person("Alice", 25)
val bob = new Person("Bob", 32)
val charlie = new Person("Charlie", 32)
for (person <- List(alice, bob, charlie)) {
person match {case Person("Alice", 25) => println("Hi Alice!")
case Person("Bob", 32) => println("Hi Bob!")
case Person(name, age) =>
println("Who are you," + age + "year-old person named" + name + "?")
}
}
// 六 正则表达式匹配
val BookExtractorRE = """Book: title=([^,]+),\s+authors=(.+)""".r
val MagazineExtractorRE = """Magazine: title=([^,]+),\s+issue=(.+)""".r
val catalog = List(
"Book: title=Programming Scala, authors=Dean Wampler, Alex Payne",
"Magazine: title=The New Yorker, issue=January 2009",
"Book: title=War and Peace, authors=Leo Tolstoy",
"Magazine: title=The Atlantic, issue=February 2009",
"BadData: text=Who put this here??"
)
for (item <- catalog) {
item match {case BookExtractorRE(title, authors) =>
println("Book \"" + title + "\", written by " + authors)
case MagazineExtractorRE(title, issue) =>
println("Magazine \"" + title + "\", issue " + issue)
case entry => println("Unrecognized entry:" + entry)
}
}
对于 case,我想强调其在“解包”中的利用:
dict = Map("Piper" -> 95, "Bob" -> 90)
dict.foreach {case (k, v) => printf("grade of %s is %s/n", k, v)
}
grade of Piper is 95
grade of Bob is 90
上述:应用了 foreach {case () => {}}
,留神 foreach
的大括号。与上面等效。
dict = Map("Piper" -> 95, "Bob" -> 90)
dict.foreach (
x => println(s"grade of ${x._1} is ${x._2}"
)
)
grade of Piper is 95
grade of Bob is 90
Scala 语法独特的中央
-
无参数办法,调用时不必加括号:
args.isEmpty
。def width: Int = if (height == 0) 0 else contents(0).length width // 调用
for
中应用<-
,相当于 Python 的in
。- 继承用关键字
extends
:class A(a: Int) extends B
。 -
单实例对象 / 动态成员变量与办法定义在
object
中:object Timer { var count = 0 def currentCount() : Long = { count += 1 count } } Timer.currentCount() // 间接调用 class Timer {...}
- 函数返回不用非要加
return
,默认最初一个表达式。 -
函数式:匿名函数作为参数,并且还能够更简洁
val numbers = List(1, -3, -5, 9, 0) numbers.filter((x) => x > 0) numbers.filter(x => x > 0) numbers.filter(_ > 0) // 一个参数且函数中仅被应用一次时
-
_
具备非凡的意义与工作(占位)// 局部利用函数 def adder(m: Int, n: Int) = m + n val add2 = adder(2, _: Int) // add2: (Int) => Int = <function1> add2(3) // res1: Int = 5 // 柯里化 currying def curriedSum(x: Int)(y: Int) = x + y curriedSum (1)(2) val onePlus = curriedSum(1)_ // 留神这里应用了 _ onePlus(2) // 模式匹配 var times = 1 times match { case 1 => "one" case 2 => "two" case _ => "other" }
Scala 的面向对象与一等公民“函数”
(1).+(2) // 3
如上,(1)
是对象,.+(2)
是办法调用。Scala 中万物皆对象。
var increase = (x: Int) => x + 1
如上,函数是一等公民,能够赋值给变量。
根本数据结构
有以下概念:
- 不可变列表
List
与可变列表ListBuffer
- 定长数组
Array
与变长数组ArrayBuffer
- 不可变汇合
Set
与可变汇合scala.collection.mutable.Set
- 映射
Map
与 可变映射scala.collection.mutable.Map
- 元组
Tuple
注意事项与 Scala 奇技淫巧
-
应用
until
是遍历数组的好方法,by
和_*
非凡意义:for (i <- 0 until.length) { } Array (1,3,5,7,9,11) // 等价于 Array[Int](1 to 11 by 2:_*) // _* 有种解包的象征
-
应用
yield
生成数组val a = Array(1, 2, 3, 4) val res1 = for (ele <- a) yield 2 * ele // 2, 4, 6, 8
-
元组的下标从
1
开始val person = (1, 2, "ABC") person._1 // 1
-
拉链操作
zip
val symbols = Array("<", "-", ">") val counts = Array(2, 10, 2) val pairs = symbols.zip(counts) // Array[(String, Int)] = Array((<, 2), (-, 10), (>, 2)) for ((s, n) <- pairs) print(s * n) <<---------->>
Map
神奇操作
// 创立
val dict = Map("Piper" -> 95, "Bob" -> 90)
val kv = Map(("Piper", 95), ("Bob", 90))
// 取值
dict("Piper")
// 合并 ++
dict ++ kv
dict.++(kv)
// 增加 +,删除 -
val n = dict + ("Tom" -> 91)
val l = dict - "Tom"
对于可变 Map
:
// += -=
dict += (("Tom", 91), ("Jerry", 87))
dict -= "Tom"
dict -= ("Jerry", "Bob")
// ++= --= 与其余汇合相分割
dict ++= List(("Tom", 91), ("Jerry", 87))
dict --= List("Jerry", "Bob")
-
::
与:::
创立列表1::3::5::Nil // List[Int] = List(1, 3, 5)
留神 ::
是右联合的:(1::(3::(5::Nil)))
。
// ::: 用来连贯列表
val L4 = L3 ::: List("Hadoop", "Hbase")
对于数据结构的探讨(List or Array?)
- 多用 List 而非 Array
- 列表的构造是递归的(即链表,
linkedList
),而数组是平等的
参考:
- scala 中 List、Array、ListBuffer、ArrayList、Set、元组区别
- Scala 学习笔记 5(汇合 Collections)