Scala 教程
Scala 教程
Scala(Scalable Language)是一门融合面向对象与函数式编程的 JVM 语言,由 Martin Odersky 于 2004 年发布,是 Apache Spark、Kafka 等大数据生态的核心语言。
本教程包含
- 基础篇:简介、安装、语法、数据类型、变量、运算符
- 控制篇:条件语句、循环、方法与函数、闭包
- 进阶篇:字符串、数组、集合、类与对象、Trait、模式匹配、异常、文件 I/O
为什么学习 Scala
- 函数式 + 面向对象双范式
- 与 Java 无缝互操作
- 大数据标配(Spark/Kafka/Flink)
- 类型安全、表达力强、代码简洁
适合人群
Java 开发者转型、大数据工程师、函数式编程爱好者。
Scala 简介
Scala 简介
Scala 是一门运行在 JVM 上的静态类型语言,名字来源于 "Scalable Language"(可扩展语言)。
核心特性
- 面向对象:一切皆对象,类、特质(Trait)、案例类(Case Class)
- 函数式:函数是一等公民,不可变集合、模式匹配
- 静态类型:强大的类型推断,兼顾安全与简洁
- 与 Java 互操作:直接调用 Java 库
- 并发友好:Akka 等并发框架基于 Scala
代码示例
object HelloWorld {
def main(args: Array[String]): Unit = {
println("Hello, Scala!")
}
}
Scala vs Java 对比
// Java
List<Integer> nums = new ArrayList<>();
for (int i = 1; i <= 5; i++) nums.add(i * 2);
// Scala
val nums = (1 to 5).map(_ * 2)
应用领域
大数据(Spark)、流处理(Kafka/Flink)、Web 框架(Play/Lift)、分布式系统(Akka)。
Scala 安装及环境配置
Scala 安装及环境配置
Scala 需要 JVM 支持,安装前请确认 JDK 环境。
1. 安装 JDK
java -version # 需要 JDK 8 或 11+(Scala 2.13 需 JDK 8+)
2. 安装 Scala
# macOS(Homebrew)
brew install scala
# Ubuntu/Debian
sudo apt install scala
# 或下载官方二进制包解压,配置 PATH
3. 验证安装
scala -version
# Scala code runner version 2.13.x
4. 推荐:使用 sbt(构建工具)
# 安装 sbt
brew install sbt
# 创建项目
sbt new scala/scala3.g8 # Scala 3
sbt new scala/hello-world.g8 # Scala 2 模板
5. IDE 支持
- IntelliJ IDEA:Scala 插件(推荐)
- VS Code:Metals 语言服务器
- 命令行:
scala file.scala直接运行脚本
Scala 基础语法
Scala 基础语法
Scala 语法简洁灵活,但与 Java 有不少差异。
Hello World
object Hello {
def main(args: Array[String]): Unit = {
println("Hello, World!")
}
}
程序结构
- object:单例对象(程序的入口)
- def:方法定义
- main:入口方法
- Unit:相当于 Java 的 void
基本语法规则
- 语句末尾分号可选
- 大小写敏感
- 类名首字母大写,方法名首字母小写
- 对象名(入口)大写开头
脚本方式运行
// hello.scala
println("Hello, Script!")
// 运行
scala hello.scala
注释
// 单行注释
/* 多行注释 */
/** 文档注释 */
包声明与导入
package com.example
import scala.collection.mutable
import java.util.{ArrayList, HashMap}Scala 数据类型
Scala 数据类型
Scala 与 Java 一样有 8 种基础类型,但全部是对象,且支持类型推断。
基础数据类型
Byte 8位有符号整数
Short 16位有符号整数
Int 32位有符号整数
Long 64位有符号整数
Float 32位浮点
Double 64位浮点
Char 16位无符号字符
Boolean true/false
String 字符串(Java String)
字面量类型推断
val i = 10 // Int
val l = 10L // Long
val f = 1.5f // Float
val d = 1.5 // Double
val c = 'A' // Char
val s = "Hello" // String
val b = true // Boolean
类型声明
val x: Int = 42 // 显式类型
val y = 42 // 类型推断
var z: Double = 3.14 // 可变变量
字符串与多行字符串
val s1 = "普通字符串"
val s2 = """多行
字符串
内容"""
val s3 = s"插值: ${s1} 长度 ${s1.length}" // 字符串插值
Unit 与 Nothing
val u: Unit = () // 相当于 void
// Nothing:所有类型的子类型,异常返回值
Any 层级
Any(所有类型的根) → AnyVal(值类型) / AnyRef(引用类型)
Nothing(所有类型的子类型)Scala 字面量
Scala 字面量
字面量是直接写在代码中的值,Scala 支持多种形式的字面量。
整数与浮点字面量
val a = 42 // 十进制
val b = 0x2A // 十六进制
val c = 0b101010 // 二进制(Scala 2.13+)
val d = 42L // Long
val e = 3.14 // Double
val f = 3.14f // Float
val g = 1e6 // 科学计数法 Double
字符与字符串字面量
val ch = 'A' // Char
val s1 = "Hello" // String
val s2 = """多行
字符串""" // 多行字符串(三引号)
布尔字面量
val t = true
val f = false
转义字符
val nl = "第一行
第二行" // 换行
val tab = "a b" // 制表符
val quote = "他说: "你好"" // 双引号
val back = "反斜杠 \\"
符号字面量(弃用)
val sym = 'symbol // Symbol 类型(旧写法,新代码用字符串)
null 与 Unit
val n = null // 引用类型空值
val u = () // Unit 字面量Scala 转义字符
Scala 转义字符
转义字符用于在字符串中表示特殊字符。
常用转义序列
\n 换行
\t 制表符
\\ 反斜杠
\" 双引号
\' 单引号
\b 退格
\f 换页
\r 回车
\uXXXX Unicode 字符(如 \u0041 = 'A')
示例
val path = "C:\\Users\\admin" // C:\Users\admin
val say = "她说: \"你好!\""
val unicode = "\u4F60\u597D" // 你好
多行字符串中无需转义
val regex = """\d+""" // 三引号内反斜杠原样
val html = """<p>HTML 内容</p>"""
字符串插值中的转义
val name = "Scala"
val msg = s"你好, \$name" // 输出: 你好, $name(字面$)
val msg2 = f"数字: ${3.14159}%.2f" // 格式化: 3.14
注意事项
- 正则表达式建议用三引号避免双重转义
- 路径建议用正斜杠
C:/Users/admin
Scala 变量
Scala 变量
Scala 有 val(不可变)和 var(可变)两种变量,推荐优先使用 val。
val 与 var
val name = "Alice" // 不可变(常量)
var age = 25 // 可变
age = 26 // 可以重新赋值
// name = "Bob" // 编译错误: val 不能重新赋值
类型标注
val x: Int = 10
val y: String = "hi"
val list: List[Int] = List(1, 2, 3)
惰性变量
lazy val config = loadConfig() // 首次访问时才计算
// 适合昂贵初始化、顺序无关的场景
变量命名
val user_name = "ok" // 下划线风格
val userName = "ok" // 驼峰风格(推荐)
val `type` = "特殊名" // 反引号包裹保留字
val 与 Java final
Scala 的 val 类似 Java 的 final 变量;但 Scala 的 val 更严格(不可变引用)。
经验
- 默认用 val,需要变更时才用 var
- 集合优先用不可变集合
- lazy val 避免重复计算
Scala 访问修饰符
Scala 访问修饰符
Scala 的访问修饰符有 private、protected 和默认(public),语义与 Java 略有差异。
三种修饰符
private 仅类内部可见
protected 类及子类可见(Java 同包可见,Scala 不同)
无修饰符 公开(public)
示例
class Person {
private var name: String = "default"
protected def greet(): Unit = println(s"Hi, $name")
def setName(n: String): Unit = name = n // 公开
}
作用域限定
// 限定到包
private[example] val x = 1 // example 包内可见
// 限定到类
private[Person] val y = 2 // Person 类内可见
protected 的差异
// Java: protected 成员同包也可访问
// Scala: protected 成员仅类及其子类可访问
class Base {
protected def f(): Unit = println("base")
}
class Sub extends Base {
def g() = f() // 子类可访问
}
// new Base().f() // 错误: 外部不可见
伴生对象访问
class Account {
private var balance = 0.0
}
object Account {
def show(a: Account) = a.balance // 伴生对象可访问私有成员
}
Scala 中类和伴生对象之间没有访问限制。
Scala 运算符
Scala 运算符
Scala 中一切运算符都是方法调用,支持中缀语法。
算术运算符
+ - * / % 加 减 乘 除 取余
val sum = 1 + 2 // 3
val sum2 = 1.+(2) // 等价写法(方法调用)
关系运算符
== != > < >= <=
注意:Scala 的 == 比较值(自动调用 equals)
逻辑运算符
&& || ! 与 或 非
val ok = a > 0 && b < 10
位运算符
& | ^ ~ << >> >>>
val r = 5 & 3 // 1
赋值运算符
+= -= *= /= %=
var n = 10
n += 5 // n = 15
比较 == 与 eq
val a = new String("hi")
val b = new String("hi")
a == b // true(值相等)
a eq b // false(引用相等)
自定义运算符
class Vector(val x: Double, val y: Double) {
def +(other: Vector) = new Vector(x + other.x, y + other.y)
}
val v1 = new Vector(1, 2)
val v2 = new Vector(3, 4)
val v3 = v1 + v2 // 使用自定义 + 运算符Scala IF...ELSE 语句
Scala IF...ELSE 语句
Scala 的 if-else 是表达式,有返回值,可以直接赋值给变量。
基本语法
val score = 85
if (score >= 90) {
println("优秀")
} else if (score >= 60) {
println("及格")
} else {
println("不及格")
}
作为表达式赋值
val grade = if (score >= 90) "A"
else if (score >= 80) "B"
else if (score >= 60) "C"
else "D"
// grade: String
单行写法
val max = if (a > b) a else b
三元运算符替代
// Java: int max = a > b ? a : b;
val max = if (a > b) a else b // Scala 无三元运算符
类型问题
val result = if (flag) 1 else "no"
// 类型推断为 Any(共同超类型)
嵌套 if
if (x > 0) {
if (y > 0) println("第一象限")
else println("第四象限")
}Scala 循环
Scala 循环
Scala 支持 while、do-while 和函数式风格的 for 推导式。
for 循环(推荐)
// 基础范围
for (i <- 1 to 5) println(i) // 1..5 包含5
for (i <- 1 until 5) println(i) // 1..4 不包含5
// 步长
for (i <- 1 to 10 by 2) println(i) // 1,3,5,7,9
// 嵌套
for (i <- 1 to 3; j <- 1 to 3) {
println(s"$i x $j")
}
for 过滤(守卫)
for (i <- 1 to 10 if i % 2 == 0) println(i) // 偶数
for (i <- 1 to 10; if i > 5; if i % 2 == 1) println(i)
for 推导式(生成集合)
val squares = for (i <- 1 to 5) yield i * i
// Vector(1, 4, 9, 16, 25)
while 循环
var n = 0
while (n < 5) {
println(n)
n += 1
}
do-while
var m = 0
do {
println(m)
m += 1
} while (m < 3)
break 与 continue
// Scala 2 无原生 break,用 Breaks 对象或递归
import scala.util.control.Breaks._
breakable {
for (i <- 1 to 10) {
if (i == 5) break
println(i)
}
}Scala 方法与函数
Scala 方法与函数
方法(def)属于类,函数是对象(FunctionN),两者都支持函数式风格。
定义方法
def add(a: Int, b: Int): Int = {
a + b
}
println(add(1, 2)) // 3
单行方法
def square(x: Int) = x * x // 返回值类型可推断
无参方法
def greeting(): Unit = println("Hello")
def greeting2 = println("Hello") // 无括号
默认参数
def greet(name: String, prefix: String = "Hello") = s"$prefix, $name"
greet("Alice") // Hello, Alice
greet("Bob", "Hi") // Hi, Bob
命名参数
def draw(x: Int, y: Int, color: String = "red") = ...
draw(color = "blue", x = 1, y = 2) // 顺序任意
可变参数
def sum(nums: Int*): Int = nums.sum
sum(1, 2, 3) // 6
sum(1, 2, 3, 4) // 10
函数字面量(匿名函数)
val addOne: Int => Int = (x: Int) => x + 1
val addTwo = (x: Int) => x + 2 // 类型推断
val multiply = (a: Int, b: Int) => a * b
高阶函数
def applyTwice(f: Int => Int, x: Int): Int = f(f(x))
applyTwice(_ + 1, 5) // 7Scala 闭包
Scala 闭包
闭包是捕获了外部自由变量的函数,可以"记住"创建时的环境。
基本闭包
var factor = 2
val multiplier = (x: Int) => x * factor // 捕获 factor
println(multiplier(5)) // 10
factor = 3 // 修改捕获的变量
println(multiplier(5)) // 15(引用最新值)
函数返回闭包
def counter(): () => Int = {
var count = 0
() => { count += 1; count }
}
val c1 = counter()
println(c1()) // 1
println(c1()) // 2
println(c1()) // 3
闭包的实际应用
// 柯里化
def addCurried(a: Int)(b: Int): Int = a + b
val add5 = addCurried(5) // 闭包:捕获 a=5
add5(10) // 15
// 回调
def repeat(n: Int, f: () => Unit): Unit = {
for (_ <- 1 to n) f()
}
repeat(3, () => println("hi"))
注意
- 闭包捕获的是变量的引用,不是值快照
- 不可变 val 捕获后保持不变
- 闭包常用于回调、柯里化、延迟计算
Scala 字符串
Scala 字符串
Scala 的 String 本质是 java.lang.String,并扩展了丰富的操作。
创建字符串
val s1 = "Hello"
val s2 = new String("World")
val s3 = """多行
字符串"""
常用方法
val s = "Hello, Scala"
s.length // 12
s.charAt(0) // H
s.substring(0, 5) // Hello
s.toUpperCase // HELLO, SCALA
s.toLowerCase // hello, scala
s.trim // 去空格
s.replace("Scala", "Java")
s.split(",") // Array("Hello", " Scala")
字符串比较
val a = "abc"
val b = "abc"
a == b // true(值比较)
a.equals(b) // true
a.startsWith("ab") // true
a.contains("bc") // true
字符串插值(推荐)
val name = "Alice"
val age = 25
val msg = s"$name is $age years old"
val expr = s"1 + 2 = ${1 + 2}"
val price = f"价格: $age%.2f 元" // 格式化
val raw = raw"\d+" // 不转义
字符串转换
"42".toInt
"3.14".toDouble
123.toString
Integer.parseInt("42") // Java 互操作
字符串构建
val sb = new StringBuilder
sb.append("Hello").append(" ").append("World")
sb.toString() // "Hello World"Scala 数组
Scala 数组
Scala 数组分为定长 Array 和可变 ArrayBuffer。
创建数组
val a1 = new Array[Int](5) // 空数组,默认0
val a2 = Array(1, 2, 3, 4, 5) // 带初值
val a3 = Array.ofDim[String](3) // 空字符串数组
访问与修改
val arr = Array(10, 20, 30)
arr(0) // 10(注意用圆括号)
arr(0) = 99 // 修改
arr.length // 3
遍历
for (x <- arr) println(x)
arr.foreach(println)
arr.map(_ * 2) // 映射
arr.filter(_ > 15) // 过滤
多维数组
val matrix = Array.ofDim[Int](3, 3)
matrix(0)(1) = 5
val m2 = Array(
Array(1, 2),
Array(3, 4)
)
数组与集合转换
val list = arr.toList
val seq = arr.toSeq
val set = arr.toSet
val back = list.toArray
ArrayBuffer(可变)
import scala.collection.mutable.ArrayBuffer
val buf = ArrayBuffer(1, 2, 3)
buf += 4 // 追加
buf ++= Array(5, 6) // 批量追加
buf.remove(0) // 删除
buf(0) // 访问
常用操作
arr.sum / arr.max / arr.min / arr.sorted
arr.indexOf(20)
arr.slice(1, 3)Scala Collection(集合)
Scala Collection(集合)
Scala 集合库功能强大,默认推荐不可变集合。
集合分类
Seq(序列) List / Vector / Range
Set(集合) Set(无重复)
Map(映射) Map(key -> value)
List(不可变)
val list = List(1, 2, 3)
list.head // 1
list.tail // List(2, 3)
list :+ 4 // List(1,2,3,4) 尾部追加(新列表)
4 :: list // List(4,1,2,3) 头部插入
list.length // 3
Set(不可变)
val set = Set(1, 2, 3, 3) // Set(1, 2, 3) 自动去重
set + 4 // Set(1,2,3,4)
set - 2 // Set(1,3)
set.contains(2) // true
Map(不可变)
val map = Map("a" -> 1, "b" -> 2)
map("a") // 1
map.get("c") // None(安全访问)
map + ("c" -> 3) // 新增
map.keys // Set(a, b)
map.values // 值集合
常用高阶操作
val nums = List(1, 2, 3, 4, 5)
nums.map(_ * 2) // List(2,4,6,8,10)
nums.filter(_ % 2 == 0) // List(2,4)
nums.reduce(_ + _) // 15
nums.foldLeft(0)(_ + _) // 15
nums.sortBy(-_) // 降序
nums.groupBy(_ % 2) // 分组
可变集合
import scala.collection.mutable
val mList = mutable.ListBuffer(1, 2)
mList += 3
val mMap = mutable.Map("a" -> 1)
mMap("b") = 2Scala Iterator(迭代器)
Scala Iterator(迭代器)
迭代器用于逐个访问集合元素,是惰性的,只能用一次。
创建迭代器
val it = Iterator(1, 2, 3, 4, 5)
val it2 = List(1, 2, 3).iterator
val it3 = (1 to 10).iterator
遍历
while (it.hasNext) {
println(it.next())
}
// 或 foreach
val it4 = Iterator(1, 2, 3)
it4.foreach(println)
常用方法
it.size // 剩余元素个数
it.length // 同上
it.isEmpty
it.toList // 转为集合
it.toArray
it.sum / it.max / it.min
映射与过滤(惰性)
val doubled = it.map(_ * 2) // 不立即执行
doubled.foreach(println) // 遍历时才计算
限制迭代器
it.take(3) // 取前3个
it.drop(2) // 跳过前2个
it.takeWhile(_ < 4) // 直到条件不满足
注意事项
- 迭代器是单次使用:遍历后即耗尽
- 迭代器操作是惰性的,适合大数据流
- 需要多次访问请转成集合
val it = Iterator(1, 2, 3)
it.foreach(println) // 1 2 3
it.foreach(println) // 空!已耗尽Scala 类和对象
Scala 类和对象
Scala 类是蓝图,object 是单例,两者构成 Scala 的面向对象基础。
定义类
class Person(val name: String, var age: Int) {
def greet(): Unit = println(s"Hi, I'm $name, $age years old")
}
val p = new Person("Alice", 25)
p.name // 读取(自动生成 getter)
p.age = 26 // 修改(自动生成 setter)
p.greet()
主构造函数参数
class Point(val x: Int, val y: Int) // val 生成 getter
// 无 val/var:参数只用于构造
class Config(host: String, port: Int) {
def url = s"$host:$port"
}
辅助构造函数
class Person(val name: String) {
def this() = this("Unknown") // 辅助构造函数
def this(name: String, age: Int) = {
this(name) // 必须调用主构造
println(s"created $name")
}
}
Object 单例对象
object MathUtils {
val PI = 3.14159
def square(x: Double) = x * x
}
MathUtils.square(3) // 9.0
伴生对象
class Circle(val r: Double) {
def area = Circle.PI * r * r // 访问伴生对象
}
object Circle {
val PI = 3.14159
def apply(r: Double) = new Circle(r) // 工厂方法
}
Circle(2.0) // apply 语法糖,不需要 new
案例类(Case Class)
case class User(id: Int, name: String)
val u = User(1, "Alice") // 无需 new
u.name // 自动 getter
u.copy(name = "Bob") // 拷贝修改
u == User(1, "Alice") // true 值比较Scala Trait(特征)
Scala Trait(特征)
Trait 类似 Java 接口,但可以包含具体实现,支持多继承,是 Scala 组合复用的核心。
定义 Trait
trait Greeter {
def greet(name: String): String // 抽象方法
def welcome(): String = "Welcome!" // 具体实现
}
混入 Trait
class EnglishGreeter extends Greeter {
override def greet(name: String) = s"Hello, $name"
}
// 混入多个 Trait
class MyClass extends BaseClass with TraitA with TraitB
富接口模式
trait Ordered[T] {
def compare(that: T): Int
def <(that: T) = compare(that) < 0 // 由 compare 派生
def >(that: T) = compare(that) > 0
}
case class Money(amount: Double) extends Ordered[Money] {
def compare(that: Money) = amount.compare(that.amount)
}
Trait 字段
trait Logger {
val level: String // 抽象字段
def log(msg: String): Unit = println(s"[$level] $msg")
}
class AppLogger extends Logger {
val level = "INFO"
}
线性化(菱形问题解决)
trait A { def f() = println("A") }
trait B extends A { override def f() = { super.f(); println("B") } }
trait C extends A { override def f() = { super.f(); println("C") } }
class D extends B with C // 调用顺序: A → C → B
new D().f() // A C B
与抽象类的选择
需要继承多个 → 用 Trait
需要构造参数 → 用抽象类(Trait 参数受限)Scala 模式匹配
Scala 模式匹配
模式匹配是 Scala 的杀手级特性,类似增强版 switch,可以匹配值、类型、结构、case class。
基本匹配
val x = 3
val result = x match {
case 1 => "one"
case 2 => "two"
case _ => "other" // 通配符
}
匹配守卫
val n = 15
n match {
case x if x % 2 == 0 => s"$x 是偶数"
case x if x % 3 == 0 => s"$x 是3的倍数"
case _ => "其他"
}
匹配类型
def describe(obj: Any): String = obj match {
case s: String => s"字符串: $s"
case i: Int => s"整数: $i"
case l: List[_] => s"列表,长度 ${l.length}"
case _ => "未知类型"
}
匹配 Case Class
case class Point(x: Int, y: Int)
case class Circle(center: Point, r: Double)
val shape: Any = Circle(Point(0, 0), 5.0)
shape match {
case Circle(Point(x, y), r) => s"圆心($x,$y) 半径$r"
case Point(x, y) => s"点($x,$y)"
case _ => "未知"
}
匹配集合
val list = List(1, 2, 3)
list match {
case Nil => "空列表"
case head :: tail => s"头部:$head 尾部:$tail"
case _ => "其他"
}
Option 匹配
val maybe: Option[Int] = Some(42)
maybe match {
case Some(v) => s"有值: $v"
case None => "无值"
}Scala 正则表达式
Scala 正则表达式
Scala 通过 scala.util.matching.Regex 封装了 Java 正则,使用更简洁。
创建正则
import scala.util.matching.Regex
val pattern = new Regex("\d+")
val pattern2 = Regex("\d+")
val pattern3 = """\d+""".r // 推荐:字符串插值.r 语法
查找
val nums = """\d+""".r
nums.findFirstIn("order 1001 total 50") // Some(1001)
nums.findAllIn("a1 b22 c333").toList // List(1, 22, 333)
nums.findFirstMatchIn("x42").map(_.start) // Some(1)
匹配判断
"""^\d+$""".r.matches("12345") // true
"""^\d+$""".r.matches("12ab") // false
提取组
val email = """([a-z]+)@([a-z]+)\.([a-z]+)""".r
val email(user, domain, tld) = "alice@example.com"
// user=alice, domain=example, tld=com
替换
val text = "price: 100, discount: 20"
"""[0-9]+""".r.replaceAllIn(text, "#") // price: #, discount: #
"""[0-9]+""".r.replaceFirstIn(text, "#")
分割
"""[,\s]+""".r.split("a, b c") // Array(a, b, c)
常用正则示例
"""\d{11}""".r // 11位数字
"""[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}""".r // 邮箱
"""https?://[\w./-]+""".r // URLScala 异常处理
Scala 异常处理
Scala 的异常处理与 Java 类似,但 try-catch-finally 是表达式。
抛出异常
throw new IllegalArgumentException("参数非法")
// 注意: Scala 没有 checked exception(不强制捕获)
捕获异常
try {
val result = riskyOperation()
println(result)
} catch {
case e: ArithmeticException => println("算术错误")
case e: Exception => println(s"其他异常: ${e.getMessage}")
} finally {
println("清理资源")
}
异常作为表达式
val result = try {
"10".toInt
} catch {
case _: NumberFormatException => 0
} finally {
println("尝试转换")
}
// result: Int
自定义异常
class BusinessException(message: String) extends Exception(message)
try {
throw new BusinessException("业务校验失败")
} catch {
case e: BusinessException => println(e.getMessage)
}
函数式错误处理
// 用 Try 替代异常(函数式风格)
import scala.util.{Try, Success, Failure}
val result: Try[Int] = Try("42".toInt)
result match {
case Success(v) => println(s"成功: $v")
case Failure(e) => println(s"失败: ${e.getMessage}")
}
// Option 风格
"42".toIntOption // Some(42)
"abc".toIntOption // None
推荐实践
- 业务错误用 Option/Try/Either 表达
- 系统异常(IO等)用 try-catch
- finally 释放资源(或 use using)
Scala 提取器(Extractor)
Scala 提取器(Extractor)
提取器是定义了 unapply 方法的对象,用于模式匹配时从对象中提取值,是实现自定义模式匹配的机制。
apply 与 unapply
object Email {
// apply: 构造
def apply(user: String, domain: String) = s"$user@$domain"
// unapply: 提取(模式匹配用)
def unapply(email: String): Option[(String, String)] = {
val parts = email.split("@")
if (parts.length == 2) Some(parts(0), parts(1))
else None
}
}
// 构造
val e = Email("alice", "example.com")
// 模式匹配提取
"alice@example.com" match {
case Email(user, domain) => s"用户$user, 域名$domain"
case _ => "非法邮箱"
}
单值提取器
object Twice {
def unapply(x: Int): Option[Int] =
if (x % 2 == 0) Some(x / 2) else None
}
8 match {
case Twice(n) => s"8 是 $n 的两倍" // 4
}
Boolean 提取器
object IsPositive {
def unapply(x: Int): Boolean = x > 0
}
5 match {
case IsPositive() => "正数"
case _ => "非正数"
}
与 Case Class 的关系
// case class 自动生成 unapply,所以可直接模式匹配
case class Point(x: Int, y: Int)
// 自定义提取器实现同样效果
object Point {
def apply(x: Int, y: Int) = new Point(x, y)
def unapply(p: Point): Option[(Int, Int)] = Some((p.x, p.y))
}Scala 文件 I/O
Scala 文件 I/O
Scala 标准库没有专门的 I/O 包,但可以直接使用 Java I/O 类,或借助 scala.io 简化读取。
读取文件(整文件)
import scala.io.Source
val source = Source.fromFile("data.txt", "UTF-8")
try {
val content = source.mkString // 全部内容
println(content)
} finally {
source.close()
}
逐行读取
val source = Source.fromFile("data.txt")
try {
for (line <- source.getLines()) {
println(line)
}
} finally {
source.close()
}
读取网络内容
val source = Source.fromURL("https://example.com")
val content = source.mkString
source.close()
写入文件
import java.io.{PrintWriter, File}
val writer = new PrintWriter(new File("out.txt"))
try {
writer.write("第一行\n")
writer.println("第二行")
} finally {
writer.close()
}
追加写入
import java.io.{FileWriter, BufferedWriter}
val bw = new BufferedWriter(new FileWriter("log.txt", true))
bw.write("追加内容\n")
bw.close()
使用 Using(自动关闭)
import scala.util.Using
Using(Source.fromFile("data.txt")) { source =>
source.mkString
}
// 自动关闭资源,返回 Try[String]
其他常用操作
import java.nio.file.{Files, Paths}
val lines = Files.readAllLines(Paths.get("data.txt"))
Files.write(Paths.get("out.txt"), "内容".getBytes)