# 前言

# 环境

如果你正在学习或者只想敲几个示例,那么强烈推荐 Scastie,一个嵌在浏览器中的线上编辑器。

如果你更喜欢 REPL 环境在自己的 scala shell 中学习和测试,则需要首先安装 sbt,使用 sbt 进入 scala shell。

# 安装 sbt

sbt 用来创建,编译,测试且运行 scala 项目。这里介绍如何安装它。

注意:安装 sbt 依赖于 java 环境

由于我的机器是 CentOS,使用 yum 进行安装。

curl https://bintray.com/sbt/rpm/rpm | sudo tee /etc/yum.repos.d/bintray-sbt-rpm.repo
sudo yum install sbt

安装成功后,敲命令 sbt console 进入 REPL 环境

$ sbt console
[info] Updated file /root/hello/project/build.properties: set sbt.version to 1.2.8
[info] Loading project definition from /root/hello/project
[info] Updating ProjectRef(uri("file:/root/hello/project/"), "hello-build")...
[info] downloading https://repo1.maven.org/maven2/org/apache/logging/log4j/log4j-core/2.11.1/log4j-core-2.11.1-tests.jar ...
[info]  [SUCCESSFUL ] org.apache.logging.log4j#log4j-core;2.11.1!log4j-core.jar(test-jar) (2985ms)
[info] Done updating.
[info] Set current project to hello (in build file:/root/hello/)
[info] Starting scala interpreter...
Welcome to Scala 2.12.7 (OpenJDK 64-Bit Server VM, Java 1.8.0_201).
Type in expressions for evaluation. Or try :help.

scala>

# 变量

scala 是一种强类型的语言,但是你可以通过 var 进行赋值,它会自动做类型推断(Type Infer)。

通过以下示例,你可以得到一个好消息,则是 scala 不用写分号!但是它必须使用双引号来表示字符串

var s = "hello, world"

println(s)

当然你也可以显式地声明变量。好吧,他这个类型声明有点怪,不过如果你写过 typescript,你对它的接受度会好很多。

var s: String = 'hello, world'

# 数据类型 (Type)

unified-types-diagram

scala 分为引用类型与值类型

以下为所有的值类型,Unit 比较特殊些,在 scala 函数必须有返回值,如果实在没有,那返回的就是 Unit,类似于 javascript 中的 undefined 吧。

  • Double
  • Float
  • Long
  • Int
  • Short
  • Byte
  • Char
  • Boolean
  • Unit

# 操作符 (Operator)

# Block

{} 包裹称作 BlockBlock 中的最后一个表达式的值为 Block 本身的值。另外 Block 与函数一样拥有一个独立的作用域。

var r = {
  val x = 1 + 1
  x + 1
}

// 3
println(r)

类似于 javascript 中的箭头表达式,不过 scala 更加灵活,以下是一个 js 的箭头表达式

const r = (x = 1 + 1, x + 1)

// 3
console.log(r)

# 函数 (Function)

scala 中,函数是带有参数的表达式

val add = (x: Int, y: Int) => x + y

类似于 python 中的 lambda 函数,与 javascript 中的单行箭头函数,他们都是匿名函数并进行赋值,见以下示例

add = lambda x, y: x + y
const add = (x, y) => x + y

# Method

与函数类似,使用 def 标记,并在其后注明返回数据类型

def add(x: Int, y: Int): Int = x + y

它也可以带有多个参数列表或者不带参数列表

def add(x: Int)(y: Int)(z: Int): Int = x + y + z

// 12
println(add(3)(4)(5))

def zero: Int = 0

// 0
println(zero)

可以使用 Block 来做 Method 的返回值

def add(x: Int, y: Int): Int = {
  var sum = x + y
  sum
}

# Class

class Cat(name: String) {
  def say(): String = "miao~"
}

var tom = new Cat("tom")
println(tom.say()) // miao~

# Object

可以理解为 单例模式

// 不需要带参数
object IdFactory {
  private var counter = 0
  def create(): Int = {
    counter += 1
    counter
  }
}

IdFactory.create() // 1
IdFactory.create() // 2
IdFactory.create() // 3

依照我的理解,它有点类似于 javascript 中的闭包,如以下 js 代码

const IdFactory = (counter = 0, () => ++counter)

IdFactory() // 1
IdFactory() // 2
IdFactory() // 3

但更像是 javascript 中的 object,如以下 js 代码

const IdFactory = {
  counter: 0,
  create () {
    return ++this.counter
  }
}

IdFactory.create() // 1
IdFactory.create() // 2
IdFactory.create() // 3

# Case Class

常用来表示不可修改数据

case class Point(x: Int, y: Int)

var p1 = Point(3, 4)
var p2 = Point(30, 40)

# Trait

trait Greeter {
  def greet(name: String): Unit = println("hello, " + name)
}

class DefaultGreeter extends Greeter

var greeter = new DefaultGreeter()
greeter.greet("shanyue")

# 引用类型

# String

scala> var str = "hello"
str: String = hello

scala> str.map(x => x.toUpper)
res4: String = HELLO

scala> str.map(x => 'A')
res7: String = AAAAA

scala> str.map(x => "A")
res10: scala.collection.immutable.IndexedSeq[String] = Vector(A, A, A, A, A)

更多参考官方文档 https://docs.scala-lang.org/overviews/collections/strings.html

# Array

scala> var a1 = Array(1, 2, 3)
a1: Array[Int] = Array(1, 2, 3)

scala> a1.map(x => x*3)
res22: Array[Int] = Array(3, 6, 9)

// 获取 Array 特定位置的值
scala> arr.apply(3)
res26: Int = 4

另外,对于 Arraymapfilter 操作符,其中 _ 代表所包含的元素

scala> var a1 = Array(1, 2, 3)
a1: Array[Int] = Array(1, 2, 3)

scala> a1 map (_ * 3)
a2: Array[Int] = Array(3, 6, 9)

# List

scala> var list = List(1, 2, 3, 4, 5)
list: List[Int] = List(1, 2, 3, 4, 5)

scala> var list2 = List(6, 7, 8, 9)
list2: List[Int] = List(6, 7, 8, 9)

// 获取 List 特定位置的值
scala> list.apply(3)
res4: Int = 4

// 获取 List 特定位置的值
scala> list(3)
res7: Int = 4

scala> list ++ list2
res8: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)

// List 是 immutable 的,无法修改其中的值
scala> list(3) = 100
<console>:26: error: value update is not a member of List[Int]
       list(3) = 100
       ^

# List 与 Array 有什么区别

Difference between Array and List in scala

  1. Array 中的值是可变的,List 是不可变的,List 更符合函数式的思维

# Seq

scala> var s = Seq(1, 1, 2)
s: Seq[Int] = List(1, 1, 2)

# Map

可以使用 key -> value 或者 (key, value) 两种形式声明 Map

scala> var m = Map(("x", 3), ("y", 4), ("z", 5))
m: scala.collection.immutable.Map[String,Int] = Map(x -> 3, y -> 4, z -> 5)

scala> var m = Map("x" -> 3, "y" -> 4, "z" -> 5)
m: scala.collection.immutable.Map[String,Int] = Map(x -> 3, y -> 4, z -> 5)

// 可以通过 get 方法获取 key
scala> m.get("x")
res7: Option[Int] = Some(3)

// get 也可以作为操作符
scala> m get "x"
res9: Option[Int] = Some(3)

// 也可以直接获取 key
scala> m("x")
res10: Int = 3

// 当直接获取 key 时,key 不存在则抛出异常
scala> m("X")
java.util.NoSuchElementException: key not found: X
  at scala.collection.MapLike$class.default(MapLike.scala:228)
  at scala.collection.AbstractMap.default(Map.scala:59)
  at scala.collection.MapLike$class.apply(MapLike.scala:141)
  at scala.collection.AbstractMap.apply(Map.scala:59)
  ... 49 elided

// 当不存在 key 时,则取默认值 100
scala> m.getOrElse("X", 100)
res13: Int = 100

// 查看 key 是否存在
scala> m.contains("X")
res16: Boolean = false

// 添加 k/v 对
scala> m.updated("a", 100)
res19: scala.collection.immutable.Map[String,Int] = Map(x -> 3, y -> 4, z -> 5, a -> 100)

// 添加 k/v 对的操作符形式
scala> m + ("a" -> 100)
res22: scala.collection.immutable.Map[String,Int] = Map(x -> 3, y -> 4, z -> 5, a -> 100)

scala> var m2 = Map("a" -> 100, "b" -> 200)
m2: scala.collection.immutable.Map[String,Int] = Map(a -> 100, b -> 200)

// 拼接两个 Map
scala> m2 ++ m
res29: scala.collection.immutable.Map[String,Int] = Map(x -> 3, y -> 4, a -> 100, b -> 200, z -> 5)

// 删除某个 key
scala> m - "x"
res31: scala.collection.immutable.Map[String,Int] = Map(y -> 4, z -> 5)

// 删除多个 key
scala> m - ("x", "y")
res33: scala.collection.immutable.Map[String,Int] = Map(z -> 5)

scala> m.keys
res38: Iterable[String] = Set(x, y, z)

scala> m.values
res42: Iterable[Int] = MapLike(3, 4, 5)

// 对 value 进行 map 转换
scala> m mapValues ((x) => x + 10)
res45: scala.collection.immutable.Map[String,Int] = Map(x -> 13, y -> 14, z -> 15)

更多 Map 操作参考官方文档 https://docs.scala-lang.org/overviews/collections/maps.html

# 流程控制

# if 语句

scala 中没有 ?: 运算符,使用 if 代替

var foo = 3
var a = if (foo == 3) 10 else 100

# for 语句

# 参考

Last Updated: 10/25/2019, 5:43:00 AM