简介 & 安装 & 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
cd
to an empty folder.- Run the command
sbt new scala/scala3.g8
to create a Scala 3 project, orsbt new scala/hello-world.g8
to 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
Vector
instead.
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.