Scala 是一门多范式编程语言,它在同一个语言中融合了面向对象编程 (OOP)函数式编程 (FP) 的强大特性。它运行在 Java 虚拟机 (JVM) 上,能够充分利用 Java 庞大而成熟的生态系统。Scala 的设计宗旨是“可伸缩的语言 (Scalable Language)”,旨在优雅地处理从小型脚本到大型分布式系统等各种复杂的编程任务。本文件将重点介绍 Scala 的基本语法。

核心思想:理解 Scala 作为一种静态类型语言,其简洁的语法如何通过类型推断、强大的表达式和对不可变性的偏向,来提供富有表现力且健壮的代码。


一、程序入口:Hello World

任何编程语言的学习都从 “Hello World” 开始。在 Scala 中,一个可执行的程序通常通过一个 object(伴生对象或独立对象)定义一个 main 方法来启动。

1
2
3
4
5
6
// HelloWorld.scala
object HelloWorld {
def main(args: Array[String]): Unit = {
println("Hello, Scala World!") // println 是一个打印到控制台的函数
}
}
  • object 关键字定义了一个单例对象。这意味着 HelloWorld 对象只有一个实例,它在程序首次访问时被创建。
  • def 关键字用于定义函数(或方法)。
  • main 是程序的入口函数,类似于 Java。它接受一个 Array[String] 类型的参数 args(用于接收命令行参数)。
  • : Unit 表示 main 函数没有返回值。Unit 类似于 Java 中的 void
  • println 是 Scala 标准库中的一个函数,用于将字符串打印到标准输出。

运行方式

  1. 保存为 HelloWorld.scala
  2. 编译:scalac HelloWorld.scala
  3. 运行:scala HelloWorld

二、变量与常量

Scala 区分为 val(常量/不可变变量)和 var(变量/可变变量)。Scala 强烈建议优先使用 val 来提高代码的可预测性和并发安全性。

  • val (Value):用于定义常量或不可变引用。一旦赋值,其值就不能再改变。
  • var (Variable):用于定义变量或可变引用。其值在声明后可以被重新赋值。

类型推断:Scala 编译器通常能够根据初始值推断出变量的类型,因此显式地声明类型是可选的,但对于清晰性有时会有帮助。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 定义一个不可变字符串常量,类型推断为 String
val message = "Hello Scala!"
println(message) // 输出:Hello Scala!

// message = "New message" // 编译错误:val 不可重新赋值

// 定义一个可变整数变量,显式指定类型 Int
var count: Int = 0
println(count) // 输出:0

count = 10 // 可以重新赋值
println(count) // 输出:10

// 可以在定义时省略类型声明,编译器会推断
val pi = 3.14159 // 类型推断为 Double
var isActive = true // 类型推断为 Boolean

三、基本数据类型

Scala 的数据类型都是对象,即使是基本类型(如 Int, Double),在底层它们也可以映射到 Java 的原生类型以优化性能。

  • 数值类型Byte, Short, Int, Long, Float, Double
  • 布尔类型Boolean (true/false)
  • 字符类型Char
  • 字符串类型String (本质上是 java.lang.String)
  • 无返回值类型Unit (类似于 Java 的 void)
  • 无值类型Null (类型层次结构的底部类型,可以赋值给任何引用类型)
  • 所有类型之父Any (所有 Scala 类型的根基类)
1
2
3
4
5
6
val myInt: Int = 42
val myDouble: Double = 3.14
val myChar: Char = 'A'
val myBoolean: Boolean = true
val myString: String = "Scala Programming"
val nothing: Unit = () // Unit 类型只有一个值,即 ()

四、函数

函数是 Scala 的核心构建块,在 Scala 中,函数是“一等公民”,这意味着函数可以像任何其他值一样被传递、存储和操作(如赋值给变量、作为参数传递给其他函数、作为函数的返回值)。

4.1 函数定义

使用 def 关键字定义函数。函数可以有参数,也可以有返回值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 定义一个有参数和返回值的函数
// 语法:def 函数名(参数名: 参数类型, ...): 返回类型 = 函数体
def add(x: Int, y: Int): Int = {
return x + y // 可以使用 return,但通常省略,Scala 函数的最后一条表达式就是其返回值
}

// 简化写法:如果函数体只有一行表达式,可以省略花括号和 return
def subtract(x: Int, y: Int): Int = x - y

// 定义一个无参数、有返回值的函数
def greeting(): String = "Hello Scala Functions!"

// 定义一个没有返回值的函数 (返回 Unit)
def printMessage(msg: String): Unit = {
println(msg)
}

// 调用函数
println(add(5, 3)) // 输出:8
println(subtract(10, 4)) // 输出:6
println(greeting()) // 输出:Hello Scala Functions!
printMessage("This is a message.") // 输出:This is a message.```

### 4.2 匿名函数 (Lambda 表达式)

匿名函数是没有名称的函数。它们常被用作高阶函数的参数。

```scala
// 定义一个匿名函数并赋值给 val
val increase = (x: Int) => x + 1
println(increase(5)) // 输出:6

// 在集合操作中使用匿名函数
val numbers = List(1, 2, 3, 4, 5) // List 是 Scala 的一个常用不可变集合
val doubledNumbers = numbers.map((x: Int) => x * 2) // map 是一个高阶函数
println(doubledNumbers) // 输出:List(2, 4, 6, 8, 10)

// 匿名函数的简写形式:如果参数在函数体内只出现一次,可以用下划线 `_` 代替
val tripledNumbers = numbers.map(_ * 3)
println(tripledNumbers) // 输出:List(3, 6, 9, 12, 15)

五、控制结构

Scala 的控制结构通常是“表达式 (Expressions)”,这意味着它们会返回一个值,这与许多其他语言中控制结构是“语句 (Statements)”不同。

5.1 If/Else 表达式

if/else 结构在 Scala 中是一个表达式,它会返回一个值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
val x = 10
val y = 20

val max = if (x > y) x else y // max 的值为 20
println(s"The maximum is $max") // 输出:The maximum is 20

val result = if (x < 0) {
"Negative"
} else if (x == 0) {
"Zero"
} else {
"Positive"
}
println(result) // 输出:Positive

5.2 循环

Scala 提供了 whiledo-while 循环,但更推荐使用 for 表达式,尤其是用于集合遍历。

While 循环

1
2
3
4
5
var i = 0
while (i < 5) {
println(s"While loop count: $i")
i += 1
}

For 表达式 (For Comprehensions)

for 表达式是 Scala 中处理集合和生成新集合的强大工具。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 简单遍历
for (i <- 1 to 3) { // 1 to 3 包含 1, 2, 3
println(s"For loop count (to): $i")
}

for (i <- 1 until 3) { // 1 until 3 包含 1, 2 (不含 3)
println(s"For loop count (until): $i")
}

val fruits = List("apple", "banana", "cherry")
for (fruit <- fruits) {
println(s"Fruit: $fruit")
}

// 带过滤器 (Guards)
for (num <- 1 to 10 if num % 2 == 0) {
println(s"Even number: $num")
}

// 生成器 (Generators) - 创建新集合
val doubledList = for (num <- numbers) yield num * 2
println(s"Doubled list: $doubledList") // 输出:Doubled list: List(2, 4, 6, 8, 10)

5.3 Match 表达式 (模式匹配)

match 表达式是 Scala 中一个非常强大的控制流结构,它比传统的 switch 语句功能更丰富,支持匹配值、类型、序列结构、case class 实例等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def describeValue(x: Any): String = x match {
case 0 => "Zero"
case 1 => "One"
case i: Int if i > 10 => s"Large integer: $i" // 匹配类型并带有条件守卫
case s: String => s"A string: '$s'"
case List(0, _*) => "A list starting with 0" // 匹配列表结构
case _ => "Something else" // 默认匹配,类似于 default
}

println(describeValue(0)) // 输出:Zero
println(describeValue(5)) // 输出:Something else
println(describeValue(15)) // 输出:Large integer: 15
println(describeValue("hello")) // 输出:A string: 'hello'
println(describeValue(List(0, 1, 2))) // 输出:A list starting with 0
println(describeValue(true)) // 输出:Something else

六、类与对象

Scala 是一种纯粹的面向对象语言,所有的值都是对象。

6.1 类 (Classes)

class 关键字用于定义一个新的类,它是创建对象的蓝图。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 最简单的类定义
class GreeterClass {
val message = "Hello from GreeterClass!"
def sayHello(): Unit = {
println(message)
}
}

// 实例化类
val greeter = new GreeterClass()
greeter.sayHello() // 输出:Hello from GreeterClass!

// 带有主构造器的类 (更常用)
// 主构造器的参数可以直接作为类的成员或者方法参数
class Person(val name: String, var age: Int) {
// val name: String - name 是一个不可变的成员变量
// var age: Int - age 是一个可变的成员变量

// 辅助构造器在这里定义,但通常不常用

def describe(): Unit = {
println(s"This person is $name and is $age years old.")
}
}

val alice = new Person("Alice", 30) // 创建 Person 类的实例
alice.describe() // 输出:This person is Alice and is 30 years old.
println(alice.name) // 可以直接访问 name (val)
alice.age = 31 // 可以修改 age (var)
alice.describe() // 输出:This person is Alice and is 31 years old.

6.2 伴生对象 (Companion Objects)

在 Scala 中,一个 class 可以拥有一个与它同名的 object,这个 object 被称为该 class 的伴生对象。伴生对象可以访问类的私有成员,常用于存放工厂方法、静态成员或工具方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Account.scala
class Account(val id: String, private var balance: Double) {
def deposit(amount: Double): Unit = {
if (amount > 0) balance += amount
}
def getBalance: Double = balance
}

object Account { // Account 类的伴生对象
// 工厂方法:创建一个新的 Account 实例
def createNewAccount(initialBalance: Double): Account = {
// 假设 id 是某种随机生成的值
new Account(java.util.UUID.randomUUID().toString, initialBalance)
}
}

val myAccount = Account.createNewAccount(100.0) // 通过伴生对象的工厂方法创建
println(s"New account ID: ${myAccount.id}, Balance: ${myAccount.getBalance}") // 输出:New account ID: ..., Balance: 100.0
myAccount.deposit(50.0)
println(s"New balance: ${myAccount.getBalance}") // 输出:New balance: 150.0

6.3 Case Class (样例类)

case class 是一种特殊(但特别常用)的类,它主要用于不可变数据的建模。编译器会自动为 case class 生成许多有用的方法,例如:

  • 构造器参数自动提升为公共的 val 成员
  • equalshashCode 方法:基于内容而非引用进行比较
  • toString 方法:提供漂亮的字符串表示
  • copy 方法:用于创建副本,并可修改部分字段
  • apply 方法:无需 new 关键字即可创建实例(在伴生对象中)
  • unapply 方法:支持模式匹配
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
case class Book(title: String, author: String, year: Int)

val book1 = Book("The Hitchhiker's Guide to the Galaxy", "Douglas Adams", 1979)
val book2 = Book("The Hitchhiker's Guide to the Galaxy", "Douglas Adams", 1979)
val book3 = Book("Scala for the Impatient", "Cay S. Horstmann", 2012)

println(book1) // 输出:Book(The Hitchhiker's Guide to the Galaxy,Douglas Adams,1979)
println(book1 == book2) // 输出:true (内容相等)
println(book1 == book3) // 输出:false

val updatedBook = book1.copy(year = 1980) // 复制并修改 year 字段
println(updatedBook) // 输出:Book(The Hitchhiker's Guide to the Galaxy,Douglas Adams,1980)

// Case Class 在模式匹配中表现出色
def getPublicationYear(item: Any): String = item match {
case Book(title, _, year) => s"$title was published in $year." // 提取字段
case _ => "Not a book."
}
println(getPublicationYear(book1)) // 输出:The Hitchhiker's Guide to the Galaxy was published in 1979.

七、集合字面量

Scala 提供了丰富且功能强大的集合库,默认的集合都是不可变的(immutable),这意味着一旦创建就不能修改。

7.1 List (列表)

有序、不可变的同类型元素序列。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
val emptyList: List[Int] = List()
val numbersList = List(1, 2, 3, 4, 5)
val fruitsList = List("apple", "banana", "orange")

// 访问元素 (索引从 0 开始)
println(numbersList(0)) // 输出:1

// 常用操作
println(numbersList.head) // 获取第一个元素:1
println(numbersList.tail) // 获取除第一个元素之外的所有元素:List(2, 3, 4, 5)
println(numbersList.isEmpty) // 判断是否为空:false
println(numbersList.length) // 长度:5
println(numbersList.contains(3)) // 是否包含:true

// 连接列表
val moreNumbers = List(6, 7)
val combinedList = numbersList ::: moreNumbers // 或者 numbersList ++ moreNumbers
println(combinedList) // 输出:List(1, 2, 3, 4, 5, 6, 7)

// map, filter 等高阶函数操作
val squaredNumbers = numbersList.map(n => n * n)
println(squaredNumbers) // 输出:List(1, 4, 9, 16, 25)

7.2 Map (映射)

键值对的不可变集合。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
val emptyMap: Map[String, Int] = Map()
val ages = Map("Alice" -> 30, "Bob" -> 25, "Charlie" -> 35)

// 访问值(使用 get 避免 KeyError,返回 Option 类型)
println(ages.get("Alice")) // 输出:Some(30)
println(ages.get("David")) // 输出:None

// 访问值(如果键不存在会抛出异常)
println(ages("Bob")) // 输出:25

// 常用操作
println(ages.contains("Charlie")) // 是否包含键:true
println(ages.keys) // 所有键:Set(Alice, Bob, Charlie)
println(ages.values) // 所有值:Iterable(30, 25, 35)

// 遍历 Map
for ((name, age) <- ages) {
println(s"$name is $age years old.")
}

7.3 Set (集合)

不包含重复元素的不可变集合。

1
2
3
4
5
6
7
8
9
10
11
12
val emptySet: Set[Int] = Set()
val uniqueNumbers = Set(1, 2, 3, 2, 4) // 自动去重
println(uniqueNumbers) // 输出:Set(1, 2, 3, 4) (顺序可能不固定)

// 常用操作
println(uniqueNumbers.contains(3)) // 是否包含:true
println(uniqueNumbers + 5) // 添加元素(返回新 Set):Set(1, 2, 3, 4, 5)
println(uniqueNumbers - 2) // 移除元素(返回新 Set):Set(1, 3, 4)

val otherSet = Set(3, 4, 5)
println(uniqueNumbers intersect otherSet) // 交集:Set(3, 4)
println(uniqueNumbers union otherSet) // 并集:Set(1, 2, 3, 4, 5)

八、注释

Scala 支持单行注释和多行注释。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 这是一个单行注释,从双斜线开始到行尾

/*
这是一个多行注释。
它可以跨越多行。
*/

/**
* 这是一个 ScalaDoc 注释,用于生成 API 文档。
* 它通常用于类、方法和字段的描述。
* @param name 这是一个参数说明
* @return 这是一个返回值说明
*/
def exampleFunction(name: String): String = {
s"Hello, $name!"
}

九、总结

本文件详细介绍了 Scala 的基本语法,包括程序入口、变量与常量、核心数据类型、函数的定义与使用、控制结构(if/else, for, match)、类与对象(普通类、伴生对象、样例类)以及常用的不可变集合(List, Map, Set)的字面量表示。掌握这些基础知识是深入学习 Scala 强大特性的基石。通过理解和实践这些基本语法,开发者可以开始构建简洁、健壮且富有表现力的 Scala 应用程序。