<!-- 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.x2.13.x 这两者不兼容,2.12.102.12.11 才兼容。

最根本的语法示例

类型的申明、控制结构(for、模式匹配、case)

// 变量val two: Int = 1 + 1var one: Int = 1var one: String = 'one'// 函数def addOne(x: Int): Int = x + 1def 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: 1a: 1, b: 2a: 2, b: 1a: 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.Randomval 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=(.+)""".rval MagazineExtractorRE = """Magazine: title=([^,]+),\s+issue=(.+)""".rval 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 95grade 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 95grade of Bob is 90

Scala 语法独特的中央

  1. 无参数办法,调用时不必加括号:args.isEmpty

    def width: Int = if (height == 0) 0 else contents(0).lengthwidth  // 调用
  2. for 中应用 <- ,相当于 Python 的 in
  3. 继承用关键字 extendsclass A(a: Int) extends B
  4. 单实例对象 / 动态成员变量与办法定义在 object 中:

    object Timer { var count = 0 def currentCount() : Long = {     count += 1     count }}Timer.currentCount()  // 间接调用class Timer { ...}
  5. 函数返回不用非要加 return ,默认最初一个表达式。
  6. 函数式:匿名函数作为参数,并且还能够更简洁

    val numbers = List(1, -3, -5, 9, 0)numbers.filter((x) => x > 0)numbers.filter(x => x > 0)numbers.filter(_ > 0)  // 一个参数且函数中仅被应用一次时
  7. _ 具备非凡的意义与工作(占位)

    // 局部利用函数def adder(m: Int, n: Int) = m + nval add2 = adder(2, _: Int)  // add2: (Int) => Int = <function1>add2(3)  // res1: Int = 5// 柯里化 curryingdef curriedSum(x: Int)(y: Int) = x + ycurriedSum (1)(2)val onePlus = curriedSum(1)_  // 留神这里应用了 _onePlus(2)// 模式匹配var times = 1times 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 奇技淫巧

  1. 应用 until 是遍历数组的好方法,by_* 非凡意义:

    for (i <- 0 until.length) { }Array (1,3,5,7,9,11)  // 等价于Array[Int](1 to 11 by 2:_*)  // _* 有种解包的象征
  2. 应用 yield 生成数组

    val a = Array(1, 2, 3, 4)val res1 = for (ele <- a) yield 2 * ele// 2, 4, 6, 8
  3. 元组的下标从 1 开始

    val person = (1, 2, "ABC")person._1  // 1
  4. 拉链操作 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)<<---------->>
  5. Map 神奇操作
// 创立val dict = Map("Piper" -> 95, "Bob" -> 90)val kv   = Map(("Piper", 95), ("Bob", 90))// 取值dict("Piper")// 合并 ++dict ++ kvdict.++(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. ::::: 创立列表

    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)