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,一门「特立独行」的语言!的更多相关文章
- 「HNOI2004」「LuoguP2292」L语言(AC自动机
题目描述 标点符号的出现晚于文字的出现,所以以前的语言都是没有标点的.现在你要处理的就是一段没有标点的文章. 一段文章T是由若干小写字母构成.一个单词W也是由若干小写字母构成.一个字典D是若干个单词的 ...
- P4715 「英语」Z 语言
题解: 平衡树维护hash值 为了支持加入删除操作 x*base^y 其中y为他是第k大 同一般的维护方法,我们不用对每个节点维护他的hash值 而是只用记录他的x值(他的位置) 然后通过updata ...
- [Luogu4715]「英语」Z 语言
luogu description 你有一个长度为\(n\)的串\(A\)和一个长度为\(m\)的串\(B\),字符集大小\(2^{31}\),且同一个串中没有相同的元素. 定义\(B\)串与\(A_ ...
- 【LOJ】#3046. 「ZJOI2019」语言
LOJ#3046. 「ZJOI2019」语言 先orz zsy吧 有一个\(n\log^3n\)的做法是把树链剖分后,形成logn个区间,这些区间两两搭配可以获得一个矩形,求矩形面积并 然后就是对于一 ...
- 「ZJOI2019」语言 解题报告
「ZJOI2019」语言 3个\(\log\)做法比较简单,但是写起来还是有点麻烦的. 大概就是树剖把链划分为\(\log\)段,然后任意两段可以组成一个矩形,就是个矩形面积并,听说卡卡就过去了. 好 ...
- Go语言:编写一个 WebsiteRacer 的函数,用来对比请求两个 URL 来「比赛」,并返回先响应的 URL。如果两个 URL 在 10 秒内都未返回结果,返回一个 error。
问题: 你被要求编写一个叫做 WebsiteRacer 的函数,用来对比请求两个 URL 来「比赛」,并返回先响应的 URL.如果两个 URL 在 10 秒内都未返回结果,那么应该返回一个 error ...
- javascript——从「最被误解的语言」到「最流行的语言」
JavaScript曾是"世界上最被误解的语言".由于它担负太多的特性.包含糟糕的交互和失败的设计,但随着Ajax的到来.JavaScript"从最受误解的编程语言演变为 ...
- 一个「学渣」从零开始的Web前端自学之路
从 13 年专科毕业开始,一路跌跌撞撞走了很多弯路,做过餐厅服务员,进过工厂干过流水线,做过客服,干过电话销售可以说经历相当的“丰富”. 最后的机缘巧合下,走上了前端开发之路,作为一个非计算机专业且低 ...
- 「MoreThanJava」当大学选择了计算机之后应该知道的
「MoreThanJava」 宣扬的是 「学习,不止 CODE」,本系列 Java 基础教程是自己在结合各方面的知识之后,对 Java 基础的一个总回顾,旨在 「帮助新朋友快速高质量的学习」. 当然 ...
- 「MoreThanJava」机器指令到汇编再到高级编程语言
「MoreThanJava」 宣扬的是 「学习,不止 CODE」,本系列 Java 基础教程是自己在结合各方面的知识之后,对 Java 基础的一个总回顾,旨在 「帮助新朋友快速高质量的学习」. 当然 ...
随机推荐
- Go语言学习 _基础04 _Map&Set
Go语言学习 _基础04 _Map&Set 1.map package map_test import ( "fmt" "testing" ) func ...
- esp8266+MQTT+DHT11(温湿度计) platformio
esp8266 + MQTT + DHT11(温湿度计) 连线 #include <Arduino.h> #include <ESP8266WiFi.h> #include & ...
- 2024御网线上Pwn方向题解
ASM Checksec检查保护 基本上保护都关闭了 64位ida逆向 程序只有一段,并且返回地址就是输入的数据,看起来就是srop了,找一下可以用的gadget 通过异或清空rax值,然后通过异或e ...
- Lua代码——使用遗传进化算法(neat算法)玩超级玛丽游戏
前文: 模拟器运行环境及Lua代码--使用遗传进化算法(neat算法)玩超级玛丽游戏 lua语言实现的neat算法代码: -- MarI/O by SethBling -- Feel free to ...
- 记录一下opencv-contrib的编译使用
一.来由 公司需求进行多图拼接算法,在opencv提供的Stitcher类当中默认的算子是ORB,我想尝试使用SIFT和SURF算子,经过一番查找发现这两个算子需要opencv的超集库支持--&quo ...
- getRawType:获取数据类型,返回结果为 Number、String、Object、Array等
function getRawType(value) { return Object.prototype.toString.call(value).slice(8, -1)}//getoRawType ...
- 基于 Github 平台的 .NET 开源项目模板 - 发布与归档 相关
CHANGELOG.md 案例 ## [1.0.1.2] - 2023-03-10 ### myproject2 _ 1.0.1: - 初步版本 简单实现 还未优化 - fix warning ## ...
- 使用 Antlr 开发领域语言
高 尚 (gaoshang1999@163.com), 软件工程师, 中国农业银行软件开发中心 简介: Antlr 是一个基于 Java 开发的功能强大的语言识别工具,Antlr 以其简介的语法和高速 ...
- vue中方法中数据已更新,但是视图却没有变化解决方法
今天在项目中碰到这样一个问题: 从父组件中传过来的props中的数据,在子组件中想加入一个变量.在created中加入变量,在方法中打印次变量是有的,但是当变量发生变化之后,视图中是响应不到的. 解决 ...
- 设计模式【3.3】-- CGLIB动态代理源码解读
cglib 动态代理 cglib介绍 CGLIB 是一个开源项目,一个强大高性能高质量的代码生成库,可以在运行期拓展 Java 类,实现 Java 接口等等.底层是使用一个小而快的字节码处理框架 AS ...