语法与库速查
把常用语法、集合操作、模式匹配、Option 与 Future 一股脑列在一页,写代码时对照查。
基础语法与表达式
| 写法 | 作用 |
|---|
val x = 1 | 不可变变量,类型由值推断为 Int |
var count = 0 | 可变变量,可重新赋值,但应尽量少用 |
val name: String = "张三" | 显式标注类型为 String,代码更清晰 |
val ratio = 3.14 | 带小数的字面量被推断为 Double |
s"共 ${List(1, 2, 3).size} 条" | 字符串插值,${} 里可以放任意表达式 |
val area = { val w = 3; w * w } | 块表达式,花括号内最后一个表达式的值就是结果 |
val grade = if (75 >= 60) "及格" else "不及格" | if 是表达式,两个分支都有返回值 |
val u: Unit = () | Unit 表示没有有用的返回值,唯一值是 () |
val ok = 1 <= 2 && 2 < 3 | 布尔表达式,&& 表示逻辑与 |
val n = 10 / 3 | 整数相除结果仍是 Int,这里得 3;要小数应写 10.0 / 3 |
字符串常用方法
| 写法 | 作用 |
|---|
"Scala".length | 字符串长度,返回 Int |
"Scala".charAt(0) | 取指定下标的字符,下标从 0 开始 |
"abcdef".substring(1, 4) | 截取 [1, 4) 区间的子串,得到 bcd |
"a,b,c".split(",").toList | 按逗号分割成 Array,再转成 List(a, b, c) |
" hi ".trim | 去掉首尾空白字符 |
"Scala".replace("a", "A") | 把所有 a 替换成 A,返回新字符串 |
"scala".toUpperCase | 转成大写;toLowerCase 则转小写 |
"42".toInt | 数字字符串转 Int,格式不对会抛 NumberFormatException |
f"总价 ${19.9}%.2f 元" | f 插值按格式符输出,%.2f 保留两位小数 |
List("Scala", "Java", "Go").mkString(" | ") | 用分隔符把集合元素拼成一个字符串 |
"abc" * 3 | 字符串重复 3 次,得到 abcabcabc |
"123".forall(_.isDigit) | 判断每个字符是否都是数字,返回 Boolean |
"%.2f".format(19.9) | String.format 风格格式化,效果与 f 插值相同 |
函数与高阶函数
| 写法 | 作用 |
|---|
def add(a: Int, b: Int): Int = a + b | 定义带参数类型和返回类型的函数 |
def greet(name: String = "同学"): String = s"你好,$name" | 默认参数,调用时可以省略 name |
greet(name = "张三") | 命名参数,参数较多时更清晰 |
def total(xs: Int*): Int = xs.sum | 可变参数,xs 在函数内是 Seq[Int] |
val square = (x: Int) => x * x | 匿名函数,也叫函数字面量 |
val inc: Int => Int = _ + 1 | 函数类型 Int => Int;下划线表示单个参数 |
def multiply(a: Int)(b: Int): Int = a * b | 柯里化,把参数拆成多个参数列表 |
val addTen = add(10, _: Int) | 部分应用,固定第一个参数得到新函数 |
List(1, 2, 3).map(_ * 2).filter(_ > 2) | map 变换后 filter 过滤,得到 List(4, 6) |
List(1, 2, 3).foreach(println) | 对每个元素执行副作用,返回 Unit |
(List(1, 2, 3).reduce(_ + _), List(1, 2, 3).foldLeft(0)(_ + _)) | reduce 用元素归约;foldLeft 带初始值,两者结果都是 6 |
List(1, 2).flatMap(n => List(n, -n)) | flatMap 先映射再把结果集合展平 |
List(1, 2, 3, 4).collect { case x if x % 2 == 0 => x * 10 } | collect 只保留偏函数有定义的元素并做变换,得到 List(20, 40) |
(List(1, 2, 3).count(_ > 1), List(1, 2, 3).exists(_ == 3), List(1, 2, 3).find(_ > 1)) | count 计数、exists 判断是否存在、find 返回第一个匹配的 Option |
集合
| 写法 | 作用 |
|---|
val xs = List(1, 2, 3); val ys: Seq[Int] = xs | List 是不可变链表;Seq 是序列的通用类型 |
val arr = Array(1, 2, 3); val v = Vector(1, 2, 3) | Array 定长但可改元素;Vector 不可变且随机访问快 |
0 :: xs | 用 :: 在头部添加元素,得到 List(0, 1, 2, 3) |
xs :+ 4 | 在尾部追加一个元素,返回新的 List |
xs ++ List(4, 5) | 拼接两个集合 |
(xs.head, xs.tail, xs.init, xs.last) | head 首元素、tail 去首、init 去末、last 末元素;空集合会抛异常 |
(xs.take(2), xs.drop(1)) | take(n) 取前 n 个;drop(n) 去掉前 n 个 |
xs.takeWhile(_ < 3) | 从头取元素直到条件第一次不满足,得到 List(1, 2) |
xs.zip(List("a", "b", "c")) | 按位置两两配对成元组 |
xs.zipWithIndex | 给每个元素附上下标,下标从 0 开始 |
(xs.sorted, xs.sortBy(-_), xs.sortWith(_ > _)) | sorted 默认升序;sortBy(-_) 实现降序;sortWith 用比较函数降序 |
xs.groupBy(_ % 2) | 按函数结果分组,返回 Map[Int, List[Int]] |
xs.distinct.mkString(", ") | distinct 去重,mkString 再用分隔符拼成字符串 |
val buf = scala.collection.mutable.ListBuffer(1, 2); buf += 3 | ListBuffer 可变、尾部追加高效,适合边遍历边累积 |
Map / Set / 元组
| 写法 | 作用 |
|---|
val m = Map("a" -> 1, "b" -> 2) | 创建不可变 Map,键值对用 -> 连接 |
(m.get("a"), m.getOrElse("z", 0)) | get 返回 Option;getOrElse 在键缺失时给默认值,这里得 (Some(1), 0) |
(m.updated("a", 10), m + ("c" -> 3)) | updated 替换已有键;+ 新增键值;都返回新 Map,原 Map 不变 |
(m.keys.toList, m.values.toList) | keys 取所有键、values 取所有值,转 List 后便于查看 |
for ((k, v) <- m) println(s"$k = $v") | 遍历 Map,用模式解构取出键和值 |
m.contains("a") | 判断某个键是否存在,返回 Boolean |
val s = Set(1, 2, 2, 3) | 创建不可变 Set,重复元素自动去重,得到 Set(1, 2, 3) |
(s.intersect(Set(2, 3, 4)), s.union(Set(4)), s.diff(Set(1))) | 分别是交集、并集、差集,都返回新 Set |
(s + 4, s - 1) | 添加或删除元素,返回新 Set,原集合不变 |
val t = ("Scala", 2.13); (t._1, t._2) | 元组可以放不同类型;_1/_2 从 1 开始按下标访问 |
m.view.mapValues(_ * 10).toMap | 2.13 的 mapValues 要通过 view 使用,返回惰性的 MapView,必须 .toMap 转回 Map;2.12 可直接 mapValues |
模式匹配与 case class
| 写法 | 作用 |
|---|
1 match { case 1 => "一"; case _ => "其他" } | match 表达式按值分支,下划线 _ 匹配其他情况 |
(-3) match { case n if n > 0 => "正"; case _ => "非正" } | case 后加 if 守卫,进一步限制匹配条件 |
(1, "Scala") match { case (i, s) => s"$i: $s" } | 元组模式,一次解构出多个值 |
List(1, 2, 3) match { case List(a, b, _*) => a + b; case _ => 0 } | 序列模式,_* 匹配剩余元素,这里得到 3 |
case class User(id: Int, name: String) | 样例类自动生成 apply、unapply、copy、equals 和 toString |
User(1, "张三").copy(name = "李四") | copy 复制对象并只修改指定字段,原对象不变 |
User.unapply(User(1, "张三")) | unapply 拆出构造参数,返回 Some((1, "张三"));模式匹配靠它工作 |
sealed trait Shape; case class Circle(r: Double) extends Shape; case object Dot extends Shape | sealed 限定子类只能写在同一文件,便于检查模式匹配是否完备 |
User(1, "张三") match { case u @ User(_, name) => s"${u.id}: $name" } | @ 把整个对象绑定到 u,同时解构出 name |
Option(42) match { case Some(v) => v; case None => 0 } | 匹配 Option 的 Some/None,安全地取出值 |
List(1, 2, 3) match { case h :: t => h + t.sum; case Nil => 0 } | 用 :: 提取首元素 h 和剩余列表 t,Nil 匹配空列表 |
Option / 异常 / 并发
| 写法 | 作用 |
|---|
val o: Option[Int] = Some(1); val n: Option[Int] = None | Option 表示可能有值(Some)或没有值(None) |
o.getOrElse(0) | 有值时取出,None 时返回默认值 |
o.map(_ * 2) | 在 Option 内部变换值,有值时得到 Some(2),None 时仍是 None |
o.flatMap(x => Some(x + 1)) | 变换结果本身是 Option 时用 flatMap,避免出现嵌套 Option |
o.toList | Option 转 List:Some(1) 转成 List(1),None 转成空列表 |
try { "42".toInt } catch { case _: NumberFormatException => 0 } finally { println("完成") } | try/catch/finally,捕获异常后给默认值,finally 总会执行 |
scala.util.Try("x".toInt).getOrElse(0) | Try 把结果封装为 Success/Failure,getOrElse 安全取默认值 |
(Right(5): Either[String, Int]).map(_ * 2) | Either 表示二选一:Right 是正常值,Left 是错误值;map 只处理 Right |
val f = scala.concurrent.Future(1 + 1)(scala.concurrent.ExecutionContext.global) | Future 做异步计算,第二个参数显式传入全局 ExecutionContext |
scala.concurrent.Await.result(f, scala.concurrent.duration.Duration(1, "s")) | Await.result 阻塞等待 Future 结果,超时时间为 1 秒 |
提示记不住方法名时,在 REPL 里对变量按 Tab 让补全弹出来,比背表格快。