简介 & 安装 & helloworld
Scala 是一门多范式的编程语言,设计初衷是要集成面向对象编程和函数式编程的各种特性。
静态类型
Scala 运行在 Java 虚拟机上,并兼容现有的 Java 程序。
Scala 源代码被编译成 Java 字节码,所以它可以运行于 JVM 之上,并可以调用现有的 Java 类库。
1 | brew install coursier/formulas/coursier && cs setup |
| Commands | Description |
|---|---|
scalac |
the Scala compiler |
scala |
the Scala REPL and script runner |
scala-cli |
Scala CLI, interactive toolkit for Scala |
sbt, sbtn |
The sbt build tool |
amm |
Ammonite is an enhanced REPL |
scalafmt |
Scalafmt is the Scala code formatter |
Hello world
cdto an empty folder.- Run the command
sbt new scala/scala3.g8to create a Scala 3 project, orsbt new scala/hello-world.g8to create a Scala 2 project. - input project name
- Run
sbt. This opens up the sbt console. - Type
~run.
scalafmt 配置 一点都不智能还需要配置,不如 gofmt
变量
val可变的var不可变
在 Scala 中,通常创建变量而不声明它们的类型。Scala 通常可以推断数据类型。
1 | val x = 1 |
也可以显示声明:
1 | val x: Int = 1 |
枚举
- 在使用模式匹配的时候,使用 sealed 修饰某个 class 的目的是让 Scala 知道所有 case 的情况,否则会编译报错。
控制结构
if/else
if/else 类似 c,但是存在返回值。所以可以直接当成三目运算符。
1 | val x = if (a < b) a else b |
match
强大的匹配表达式是 Scala 的一大特点,scala 的 match 非常强大。
1 | val result = i match { |
该match表达式不仅限于整数,它可以与任何数据类型一起使用,包括布尔值:
1 | val booleanAsString = bool match { |
match这是一个用作方法主体的示例,并与许多不同的类型进行匹配:
1 | def getClassAsString(x: Any):String = x match { |
try/catch
1 | try { |
for
1 | for (arg <- args) println(arg) |
您还可以将yield关键字添加到 for 循环以创建产生结果的 for 表达式。这是一个将序列 1 到 5 中的每个值加倍的 for 表达式:
1 | val x = for (i <- 1 to 5) yield i * 2 |
另一种 for
1 | val fruits = List("apple", "banana", "lime", "orange") |
while
Scala 也有while和do/while循环。这是它们的一般语法:
1 | // while loop |
class
通过 val 和 var 来控制成员变量的可变性。
1 | class Person(val age: Int, var name: String) { |
getter 和 setter 方法:
1 | class Counter { |
constructor function
scala 的构造函数非常牛逼,Scala的主构造器是整个类体
1 | class Person(var firstName: String, var lastName: String) { |
auxiliary class constructors 辅助构造函数
- 使用
this命名 - 其它类似函数重载
1 | val DefaultCrustSize = 12 |
1 | val p1 = new Pizza(DefaultCrustSize, DefaultCrustType) |
带默认值的构造函数
1 | class Socket(var timeout: Int = 2000, var linger: Int = 3000) { |
方法
1 | def add(a: Int, b: Int): Int = { |
匿名函数
1 | scala> val boo = (i: Int) => i * 2 |
可以配合 map , filter, reduce使用
1 | scala> var ints = List.range(0, 10) |
1 | a 方法 b |
上面二者是等价的。所以:
1 | books flatMap (s => s.toList) |
闭包
闭包是一个函数,返回值依赖于声明在函数外部的一个或多个变量。
1 | var factor = 3 |
接口
scala trait 相当于 java interface,但是更像是 java 的抽象类。
1 | trait Speaker { |
一旦你有了这些小块,你就可以Dog通过扩展它们来创建一个类,并实现必要的方法:
1 | class Dog extends Speaker with TailWagger with Runner { |
- 使用
extends和with实现多扩展
可以在变量初始化的时候动态追加特征☕️
1 | trait Stop { |
抽象类
1 | abstract class Animal(name: String = "Animal") { |
Object
object的构造器不接受参数传递。
单例对象
使用object中的常量或方法,通过object名直接调用,对象构造器在对象第一次被使用时调用(如果某对象一直未被使用,那么其构造器也不会被调用)。
Scala并没有提供Java那样的静态方法或静态字段,但是,可以采用object关键字实现单例对象,具备和Java静态方法同样的功能。
1 | object Person { |
伴生对象
当单例对象与某个类同名时,它被称为这个类的“伴生对象”。类和它的伴生对象必须存在于同一个文件中,而且可以相互访问私有成员(字段和方法)。
apply 方法和 update 方法
apply 约定如下:用括号传递给变量(对象)一个或多个参数时,Scala 会把它转换成对apply方法的调用;
- 用括号传递给 变量 调用 class 的 apply
- 用括号传递给 对象 调用 object 的 apply
1 | class TestApplyClassAndObject { |
在Scala中,伴生对象有一个重要用途,那就是,我们通常将伴生对象作为工厂使用,这样就不需要使用关键字new来创建一个实例化对象了。
1 | class Car(name: String){ |
update 与此相似的,当对带有括号并包括一到若干参数的对象进行赋值时,编译器将调用对象的update方法,在调用时,是把括号里的参数和等号右边的对象一起作为update方法的输入参数来执行调用
1 | val myStrArr = new Array[String](3) //声明一个长度为3的字符串数组,每个数组元素初始化为null |
从上面可以看出,在进行元组赋值的时候,之所以没有采用Java中的方括号myStrArr[0],而是采用圆括号的形式,myStrArr(0),是因为存在上述的update方法的机制。
高级数据结构

ArrayBuffer
类似于 c++ 的 vector
要使用ArrayBuffer你必须先导入它:
1 | import scala.collection.mutable.ArrayBuffer |
C
1 | val ints = ArrayBuffer[Int]() |
R
1 | arr(2) |
U
推荐使用 ++,而不是 append 耗时比较
1 | // add one element |
D
1 | // remove one element |
作为简要概述,您可以使用以下几种方法ArrayBuffer:
1 | val a = ArrayBuffer(1, 2, 3) // ArrayBuffer(1, 2, 3) |
Array 类似于 python tuple,ArrayBuffer 类似于 python list。可以调用toArray()和toBuffer()转换。
List
The List class is a linear, immutable sequence. All this means is that it’s a linked-list that you can’t modify. Any time you want to add or remove List elements, you create a new List from an existing List.
初始化
1 | val names = List("Joel", "Chris", "Ed") |
添加元素
由于 List 是单链表结构,所以在首尾添加快,中间慢。
Tip: If you want to prepend and append elements to an immutable sequence, use
Vectorinstead.
1 | val a = List(1,2,3) |
You prepend elements to a List like this:
1 | val b = 0 +: a |
and this:
1 | val b = List(-1, 0) ++: a |
The REPL shows how this works:
1 | scala> val b = 0 +: a |
Vector
The Vector class is an indexed, immutable sequence.
创建,添加类似 List
Map (mutable)
To use the mutable Map class, first import it:
1 | import scala.collection.mutable.Map |
初始化
1 | val states = Map( |
Add
Now you can add a single element to the Map with +=, like this:
1 | states += ("AL" -> "Alabama") |
You also add multiple elements using +=:
1 | states += ("AR" -> "Arkansas", "AZ" -> "Arizona") |
You can add elements from another Map using ++=:
1 | states ++= Map("CA" -> "California", "CO" -> "Colorado") |
D
You remove elements from a Map using -= and --= and specifying the key values, as shown in the following examples:
1 | states -= "AR" |
U
You update Map elements by reassigning their key to a new value:
1 | states("AK") = "Alaska, A Really Big State" |
Traversing a Map
a nice way to loop over all of the map elements is with this for loop syntax:
1 | for ((k,v) <- ratings) println(s"key: $k, value: $v") |
Set
The Scala Set class is an iterable collection with no duplicate elements.
Scala has several more Set classes, including SortedSet, LinkedHashSet, and more. Please see the Set class documentation for more details on those classes.
Tuple
元组是一个简洁的类,提供存储异构数据的方法。元组不可迭代。
1 | val t = (3, "Three", new Person("Al")) |
访问只能使用 ._id 的方式访问,其中 id 从 1 开始
1 | scala> var t = (1, 2, 3, 1.1) |
可以使用类似 python golang 的初始化方式:
1 | scala> val(x, y, z) = (3, "Three", new Person("David")) |
Iterator
1 | object Test { |
SBT & SCALATEST
- The sbt build tool
- ScalaTest, a code testing framework
SBT
Directory structure
1 | build.sbt |
编译项目:
- 可以使用
sbt run来构建项目 - 也可以使用
sbt交互式的构建项目 sbt reload拉取镜像sbt package打包成 jar 包
Scala test
ctrl + shift + t || command + shift + t 快速创建 test
ScalaTest TDD 风格
1 | package pizza |
然后使用 sbt test 指令就可以运行了
ScalaTest BDD 风格
1 | package simpletest |
- BDD 使用
AnyFunSpec,TDD 使用AnyFunSuite - 使用
pending来标记还没有编写的 test
Functional Programming
Functional programming is a style of programming that emphasizes writing applications using only pure functions and immutable values.
pure function
- 函数的 output 取决于 input
- 函数不会改变任何隐藏状态,例如 verilog 的寄存器
- 函数不从外界读取和输出信息
- 仅存在副作用,任何返回
Unit的函数都是副作用的
任何时候你用相同的输入值调用一个纯函数,你总是会得到相同的结果。
纯函数:
scala.math.abs不纯函数:集合类上的
foreach,调用了STDOUT
FP applications have a core of pure functions combined with other impure functions to interact with the outside world.
处理空值
类似于 golang 返回 (String, error) 一样,但是 scala 没有这种处理逻辑,所以引入了 Option Some None
1 | def toInt(s: String): Option[Int] = { |
处理异常:
使用 match
1 | toInt(x) match { |
- Post title:scala
- Post author:auggie
- Create time:2022-11-07 15:56:36
- Post link:https://ruanjiancheng.github.io/2022/11/07/scala/
- Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.