入门 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 + 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 语法独特的地方

  1. 无参数方法,调用时不用加括号:args.isEmpty
def width: Int = if (height == 0) 0 else contents(0).length

width  // 调用
  1. for 中使用 <- ,相当于 Python 的 in

  2. 继承用关键字 extendsclass A(a: Int) extends B

  3. 单实例对象 / 静态成员变量与方法定义在 object 中:

object Timer {
var count = 0
def currentCount() : Long = {
count += 1
count
}
} Timer.currentCount() // 直接调用 class Timer {
...
}
  1. 函数返回不必非要加 return ,默认最后一个表达式。

  2. 函数式:匿名函数作为参数,并且还可以更简洁

val numbers = List(1, -3, -5, 9, 0)

numbers.filter((x) => x > 0)
numbers.filter(x => x > 0)
numbers.filter(_ > 0) // 一个参数且函数中仅被使用一次时
  1. _ 具有特殊的意义与工作(占位)
// 部分应用函数
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 奇技淫巧

  1. 使用 until 是遍历数组的好办法,by_* 特殊意义:
for (i <- 0 until.length) { }

Array (1,3,5,7,9,11)  // 等价于
Array[Int](1 to 11 by 2:_*) // _* 有种解包的意味
  1. 使用 yield 生成数组
val a = Array(1, 2, 3, 4)
val res1 = for (ele <- a) yield 2 * ele
// 2, 4, 6, 8
  1. 元组的下标从 1 开始
val person = (1, 2, "ABC")
person._1 // 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)
<<---------->>
  1. 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. ::::: 创建列表
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,一门「特立独行」的语言!的更多相关文章

  1. 「HNOI2004」「LuoguP2292」L语言(AC自动机

    题目描述 标点符号的出现晚于文字的出现,所以以前的语言都是没有标点的.现在你要处理的就是一段没有标点的文章. 一段文章T是由若干小写字母构成.一个单词W也是由若干小写字母构成.一个字典D是若干个单词的 ...

  2. P4715 「英语」Z 语言

    题解: 平衡树维护hash值 为了支持加入删除操作 x*base^y 其中y为他是第k大 同一般的维护方法,我们不用对每个节点维护他的hash值 而是只用记录他的x值(他的位置) 然后通过updata ...

  3. [Luogu4715]「英语」Z 语言

    luogu description 你有一个长度为\(n\)的串\(A\)和一个长度为\(m\)的串\(B\),字符集大小\(2^{31}\),且同一个串中没有相同的元素. 定义\(B\)串与\(A_ ...

  4. 【LOJ】#3046. 「ZJOI2019」语言

    LOJ#3046. 「ZJOI2019」语言 先orz zsy吧 有一个\(n\log^3n\)的做法是把树链剖分后,形成logn个区间,这些区间两两搭配可以获得一个矩形,求矩形面积并 然后就是对于一 ...

  5. 「ZJOI2019」语言 解题报告

    「ZJOI2019」语言 3个\(\log\)做法比较简单,但是写起来还是有点麻烦的. 大概就是树剖把链划分为\(\log\)段,然后任意两段可以组成一个矩形,就是个矩形面积并,听说卡卡就过去了. 好 ...

  6. Go语言:编写一个 WebsiteRacer 的函数,用来对比请求两个 URL 来「比赛」,并返回先响应的 URL。如果两个 URL 在 10 秒内都未返回结果,返回一个 error。

    问题: 你被要求编写一个叫做 WebsiteRacer 的函数,用来对比请求两个 URL 来「比赛」,并返回先响应的 URL.如果两个 URL 在 10 秒内都未返回结果,那么应该返回一个 error ...

  7. javascript——从「最被误解的语言」到「最流行的语言」

    JavaScript曾是"世界上最被误解的语言".由于它担负太多的特性.包含糟糕的交互和失败的设计,但随着Ajax的到来.JavaScript"从最受误解的编程语言演变为 ...

  8. 一个「学渣」从零开始的Web前端自学之路

    从 13 年专科毕业开始,一路跌跌撞撞走了很多弯路,做过餐厅服务员,进过工厂干过流水线,做过客服,干过电话销售可以说经历相当的“丰富”. 最后的机缘巧合下,走上了前端开发之路,作为一个非计算机专业且低 ...

  9. 「MoreThanJava」当大学选择了计算机之后应该知道的

    「MoreThanJava」 宣扬的是 「学习,不止 CODE」,本系列 Java 基础教程是自己在结合各方面的知识之后,对 Java 基础的一个总回顾,旨在 「帮助新朋友快速高质量的学习」. 当然 ...

  10. 「MoreThanJava」机器指令到汇编再到高级编程语言

    「MoreThanJava」 宣扬的是 「学习,不止 CODE」,本系列 Java 基础教程是自己在结合各方面的知识之后,对 Java 基础的一个总回顾,旨在 「帮助新朋友快速高质量的学习」. 当然 ...

随机推荐

  1. Go语言学习 _基础04 _Map&Set

    Go语言学习 _基础04 _Map&Set 1.map package map_test import ( "fmt" "testing" ) func ...

  2. esp8266+MQTT+DHT11(温湿度计) platformio

    esp8266 + MQTT + DHT11(温湿度计) 连线 #include <Arduino.h> #include <ESP8266WiFi.h> #include & ...

  3. 2024御网线上Pwn方向题解

    ASM Checksec检查保护 基本上保护都关闭了 64位ida逆向 程序只有一段,并且返回地址就是输入的数据,看起来就是srop了,找一下可以用的gadget 通过异或清空rax值,然后通过异或e ...

  4. Lua代码——使用遗传进化算法(neat算法)玩超级玛丽游戏

    前文: 模拟器运行环境及Lua代码--使用遗传进化算法(neat算法)玩超级玛丽游戏 lua语言实现的neat算法代码: -- MarI/O by SethBling -- Feel free to ...

  5. 记录一下opencv-contrib的编译使用

    一.来由 公司需求进行多图拼接算法,在opencv提供的Stitcher类当中默认的算子是ORB,我想尝试使用SIFT和SURF算子,经过一番查找发现这两个算子需要opencv的超集库支持--&quo ...

  6. getRawType:获取数据类型,返回结果为 Number、String、Object、Array等

    function getRawType(value) { return Object.prototype.toString.call(value).slice(8, -1)}//getoRawType ...

  7. 基于 Github 平台的 .NET 开源项目模板 - 发布与归档 相关

    CHANGELOG.md 案例 ## [1.0.1.2] - 2023-03-10 ### myproject2 _ 1.0.1: - 初步版本 简单实现 还未优化 - fix warning ## ...

  8. 使用 Antlr 开发领域语言

    高 尚 (gaoshang1999@163.com), 软件工程师, 中国农业银行软件开发中心 简介: Antlr 是一个基于 Java 开发的功能强大的语言识别工具,Antlr 以其简介的语法和高速 ...

  9. vue中方法中数据已更新,但是视图却没有变化解决方法

    今天在项目中碰到这样一个问题: 从父组件中传过来的props中的数据,在子组件中想加入一个变量.在created中加入变量,在方法中打印次变量是有的,但是当变量发生变化之后,视图中是响应不到的. 解决 ...

  10. 设计模式【3.3】-- CGLIB动态代理源码解读

    cglib 动态代理 cglib介绍 CGLIB 是一个开源项目,一个强大高性能高质量的代码生成库,可以在运行期拓展 Java 类,实现 Java 接口等等.底层是使用一个小而快的字节码处理框架 AS ...