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

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

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

  2. 继承用关键字 extends :class 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. 华为云-容器引擎CCE-部署Nginx应用

    环境准备 注册华为云账号 复制下面地址到浏览器地址栏(https://reg.huaweicloud.com/registerui/cn/register.html?fromacct=c76cea9f ...

  2. 轻松玩转pandas

    文章目录 1.pandas简介 2.pandas应用 3.pandas安装 4.Pandas 数据结构 - Series 5.Pandas 数据结构 - DataFrame 6.Pandas CSV ...

  3. HTTP相关返回值异常如何解决(上篇)

    ​ 今天我们讲讲HTTP相关返回值异常如何解决(实例持续更新中) 一.HTTP介绍 HTTP(超文本传输协议,Hypertext Transfer Protocol)是用于在网络上进行数据交换的应用层 ...

  4. ubuntu系统安装wps后语言是英文的问题

    如果安装ubuntu系统后,在里面安装wps的时候,发现都是英文,无法切换为中文,可以这样操作. 此时点击这里新建一个word空白文档 点击这里新建文档 点击这里显示语言 点击下面的 简体中文 再点击 ...

  5. WSL(Ubuntu)连接 Windows 的 USB 设备(完结)

    前言 最近使用 Linux 通过串口与设备通信,之前使用 Linux 都是在 VMware 里创建虚拟机,该平台下若有串口通信需求,有专门的按键功能切换很方便. 但切换了 WSL2 (windows ...

  6. k8s之基础篇

    相关概念: kube-apierver: 控制平面组件,负责kubernetes api, 处理接受的请求工作 kube-controller-manager: 控制平面组件, 负责运行控制器进程 k ...

  7. python命令行工具之Click

    Click 是一个简洁好用的Python模块,它能用尽量少的代码实现漂亮的命令行界面.它不仅开箱即用.还能支持高度自定义的配置. 示例: import click @click.command() @ ...

  8. kali 安装 shodan

    声明! 学习视频来自B站up主 泷羽sec 有兴趣的师傅可以关注一下,如涉及侵权马上删除文章,笔记只是方便各位师傅的学习和探讨,文章所提到的网站以及内容,只做学习交流,其他均与本人以及泷羽sec团队无 ...

  9. uni-app 使用笔记

    1.前言 也不知道是我水平菜还是文档太烂,这个框架使用的过程中踩了无数的坑,屡次想砸键盘,最后贫穷让我平复了心情.为了纪念这段操蛋的日子,我决定把这些坑都记录下来. 2.数据请求 在实际的项目中,数据 ...

  10. 使用 httputils + protostuff 实现高性能 rpc

    1.先讲讲 protostuf protostuf 一直是高性能序列化的代表之一.但是用起来,可难受了,你得先申明 protostuf 配置文件,并且要把这个配置文件转成类.所以必然要学习新语法.新工 ...