使用 Scala 有很多好处,尤其是 Scala 3。很难列出 Scala 的所有好处,但“十大”好处可能如下所示
- Scala 融合了函数式编程 (FP) 和面向对象编程 (OOP)
- Scala 是静态类型的,但通常感觉像动态类型的语言
- Scala 的语法简洁,但仍然可读;它通常被称为富有表现力
- Scala 2 中的隐式是一个决定性特征,它们在 Scala 3 中得到了改进和简化
- Scala 与 Java 无缝集成,因此您可以创建包含 Scala 和 Java 混合代码的项目,并且 Scala 代码可以轻松使用数千个现有的 Java 库
- Scala 可以用于服务器,也可以在浏览器中与 Scala.js 一起使用
- Scala 标准库有数十种预构建的函数式方法,可以节省您的时间,并大大减少编写自定义
for
循环和算法的需要 - “最佳实践”已内置到 Scala 中,它支持不可变性、匿名函数、高阶函数、模式匹配、默认情况下不可扩展的类等
- Scala 生态系统提供世界上最现代的 FP 库
- 强大的类型系统
1) FP/OOP 融合
与任何其他语言相比,Scala 更支持 FP 和 OOP 范式的融合。正如 Martin Odersky 所说,Scala 的本质是在类型化设置中融合函数式和面向对象编程,其中
- 逻辑函数和
- 模块化对象
模块化的最佳示例可能是标准库中的类。例如,List
被定义为一个类,从技术上讲它是一个抽象类,并且可以像这样创建一个新实例
val x = List(1, 2, 3)
然而,对程序员来说,一个简单的 List
实际上是由几种专门类型的组合构建的,包括名为 Iterable
、Seq
和 LinearSeq
的特质。这些类型同样由其他小型模块化代码单元组成。
除了从一系列模块化特质构建 List
这样的类型之外,List
API 还包含几十个其他方法,其中许多是高阶函数
val xs = List(1, 2, 3, 4, 5)
xs.map(_ + 1) // List(2, 3, 4, 5, 6)
xs.filter(_ < 3) // List(1, 2)
xs.find(_ > 3) // Some(4)
xs.takeWhile(_ < 3) // List(1, 2)
在这些示例中,列表中的值不能被修改。List
类是不可变的,因此所有这些方法都返回新值,如每条注释中的数据所示。
2) 动态感觉
Scala 的类型推断通常会让语言感觉是动态类型的,即使它是静态类型的。变量声明就是如此
val a = 1
val b = "Hello, world"
val c = List(1,2,3,4,5)
val stuff = ("fish", 42, 1_234.5)
将匿名函数传递给高阶函数时也是如此
list.filter(_ < 4)
list.map(_ * 2)
list.filter(_ < 4)
.map(_ * 2)
以及定义方法时
def add(a: Int, b: Int) = a + b
在 Scala 3 中,这种情况比以往任何时候都更加明显,例如使用联合类型时
// union type parameter
def help(id: Username | Password) =
val user = id match
case Username(name) => lookupName(name)
case Password(hash) => lookupPassword(hash)
// more code here ...
// union type value
val b: Password | Username = if (true) name else password
3) 简洁的语法
Scala 是一种低仪式,“简洁但仍然可读”的语言。例如,变量声明很简洁
val a = 1
val b = "Hello, world"
val c = List(1,2,3)
创建特质、类和枚举等类型很简洁
trait Tail:
def wagTail(): Unit
def stopTail(): Unit
enum Topping:
case Cheese, Pepperoni, Sausage, Mushrooms, Onions
class Dog extends Animal, Tail, Legs, RubberyNose
case class Person(
firstName: String,
lastName: String,
age: Int
)
高阶函数很简洁
list.filter(_ < 4)
list.map(_ * 2)
所有这些表达式以及更多表达式都很简洁,并且仍然非常可读:我们称之为表达。
4) 隐式,简化
Scala 2 中的隐式是主要的独特设计特征。它们代表了抽象上下文的基本方式,采用统一范例来满足各种用例,其中包括
- 实现类型类
- 建立上下文
- 依赖注入
- 表达能力
从那时起,其他语言采用了类似的概念,所有这些概念都是术语推断核心思想的变体:给定一个类型,编译器会合成一个具有该类型的“规范”术语。
虽然隐式是 Scala 2 中的一个决定性功能,但在 Scala 3 中其设计得到了极大的改进
- 有一种定义“给定”值的方法
- 有一种引入隐式参数和参数的方法
- 有一种单独的方式来导入给定值,这种方式不允许它们隐藏在正常的导入中
- 有一种定义隐式转换的方法,该方法明确标记为隐式转换,并且不需要特殊语法
这些更改的好处包括
- 新设计避免了功能交互,使语言更加一致
- 它使隐式更容易学习,更难滥用
- 它极大地提高了使用隐式的 95% Scala 程序的清晰度
- 它有可能以一种原则性的方式启用术语推理,这种方式也是可访问和友好的
这些功能在其他部分中进行了详细描述,因此请参阅 上下文抽象简介,以及 given
和 using
子句 部分以了解更多详细信息。
5) 无缝的 Java 集成
Scala/Java 交互在很多方面都是无缝的。例如
- 您可以在 Scala 项目中使用所有数千个可用的 Java 库
- Scala
String
本质上是一个 JavaString
,其中添加了其他功能 - Scala 无缝地使用 Java java.time._ 包中的日期/时间类
您还可以在 Scala 中使用 Java 集合类,并且为了赋予它们更多功能,Scala 包含方法,以便您可以将它们转换为 Scala 集合。
虽然几乎每次交互都是无缝的,但 “与 Java 交互”章节 演示了如何更好地一起使用一些功能,包括如何使用
- Scala 中的 Java 集合
- Scala 中的 Java
Optional
- Scala 中的 Java 接口
- Java 中的 Scala 集合
- Java 中的 Scala
Option
- Java 中的 Scala 特性
- 在 Java 代码中抛出异常的 Scala 方法
- Java 中的 Scala 可变参数
有关这些功能的更多详细信息,请参阅该章节。
6) 客户端和服务器
Scala 可与出色的框架一起在服务器端使用
- Play Framework 让你能够构建高度可扩展的服务器端应用程序和微服务
- Akka Actors 让你能够使用 Actor 模型极大地简化分布式和并发软件应用程序
Scala 还可以与 Scala.js 项目 一起在浏览器中使用,该项目是 JavaScript 的类型安全替代品。Scala.js 生态系统拥有数十个库,让你能够在浏览器中使用 React、Angular、jQuery 和许多其他 JavaScript 和 Scala 库。
除了这些工具之外,Scala Native 项目“是一个专门为 Scala 设计的优化预先编译器和轻量级托管运行时”。它让你能够使用纯 Scala 代码构建“系统”样式的二进制可执行应用程序,并且还让你能够使用更低级别的基元。
7) 标准库方法
你几乎不需要再编写自定义 for
循环,因为 Scala 标准库中的数十个预构建函数方法既可以节省你的时间,又可以帮助在不同的应用程序中使代码保持一致。
以下示例显示了一些内置集合方法,除了这些之外还有很多。虽然这些都使用 List
类,但相同的方法适用于其他集合类,如 Seq
、Vector
、LazyList
、Set
、Map
、Array
和 ArrayBuffer
。
以下是一些示例
List.range(1, 3) // List(1, 2)
List.range(start = 1, end = 6, step = 2) // List(1, 3, 5)
List.fill(3)("foo") // List(foo, foo, foo)
List.tabulate(3)(n => n * n) // List(0, 1, 4)
List.tabulate(4)(n => n * n) // List(0, 1, 4, 9)
val a = List(10, 20, 30, 40, 10) // List(10, 20, 30, 40, 10)
a.distinct // List(10, 20, 30, 40)
a.drop(2) // List(30, 40, 10)
a.dropRight(2) // List(10, 20, 30)
a.dropWhile(_ < 25) // List(30, 40, 10)
a.filter(_ < 25) // List(10, 20, 10)
a.filter(_ > 100) // List()
a.find(_ > 20) // Some(30)
a.head // 10
a.headOption // Some(10)
a.init // List(10, 20, 30, 40)
a.intersect(List(19,20,21)) // List(20)
a.last // 10
a.lastOption // Some(10)
a.map(_ * 2) // List(20, 40, 60, 80, 20)
a.slice(2, 4) // List(30, 40)
a.tail // List(20, 30, 40, 10)
a.take(3) // List(10, 20, 30)
a.takeRight(2) // List(40, 10)
a.takeWhile(_ < 30) // List(10, 20)
a.filter(_ < 30).map(_ * 10) // List(100, 200, 100)
val fruits = List("apple", "pear")
fruits.map(_.toUpperCase) // List(APPLE, PEAR)
fruits.flatMap(_.toUpperCase) // List(A, P, P, L, E, P, E, A, R)
val nums = List(10, 5, 8, 1, 7)
nums.sorted // List(1, 5, 7, 8, 10)
nums.sortWith(_ < _) // List(1, 5, 7, 8, 10)
nums.sortWith(_ > _) // List(10, 8, 7, 5, 1)
8) 内置最佳实践
Scala 惯用法以多种方式鼓励最佳实践。对于不可变性,建议你创建不可变的 val
声明
val a = 1 // immutable variable
你还应该使用不可变集合类,如 List
和 Map
val b = List(1,2,3) // List is immutable
val c = Map(1 -> "one") // Map is immutable
用例类主要用于领域建模,并且其参数是不可变的
case class Person(name: String)
val p = Person("Michael Scott")
p.name // Michael Scott
p.name = "Joe" // compiler error (reassignment to val name)
如前一节所示,Scala 集合类支持高阶函数,你可以将方法(未显示)和匿名函数传递给它们
a.dropWhile(_ < 25)
a.filter(_ < 25)
a.takeWhile(_ < 30)
a.filter(_ < 30).map(_ * 10)
nums.sortWith(_ < _)
nums.sortWith(_ > _)
match
表达式让你能够使用模式匹配,它们真正是返回值的表达式
val numAsString = i match {
case 1 | 3 | 5 | 7 | 9 => "odd"
case 2 | 4 | 6 | 8 | 10 => "even"
case _ => "too big"
}
val numAsString = i match
case 1 | 3 | 5 | 7 | 9 => "odd"
case 2 | 4 | 6 | 8 | 10 => "even"
case _ => "too big"
由于它们可以返回值,因此它们通常用作方法的主体
def isTruthy(a: Matchable) = a match {
case 0 | "" => false
case _ => true
}
def isTruthy(a: Matchable) = a match
case 0 | "" => false
case _ => true
9) 生态系统库
用于函数式编程的 Scala 库,如 Cats 和 Zio,是 FP 社区中的领先库。所有这些流行语,如高性能、类型安全、并发、异步、资源安全、可测试、函数式、模块化、二进制兼容、高效、效果/效果等,都可以用于这些库。
我们可以在此处列出数百个库,但幸运的是,它们都列在另一个位置:有关这些详细信息,请参阅 “Awesome Scala” 列表。
10) 强大的类型系统
Scala 具有强大的类型系统,并且在 Scala 3 中得到了进一步的改进。Scala 3 的目标在早期就已定义,与类型系统相关的目标包括
- 简化
- 消除不一致
- 安全性
- 人体工程学
- 性能
简化通过几十项已更改和已删除的功能实现。例如,从 Scala 2 中重载的 implicit
关键字到 Scala 3 中的 given
和 using
术语的更改使语言更加清晰,尤其对于初学者而言。
消除不一致与 Scala 3 中几十项 已删除的功能、已更改的功能 和 已添加的功能 相关。此类别中一些最重要的功能是
- 相交类型
- 并集类型
- 隐式函数类型
- 依赖函数类型
- 特征参数
- 泛型元组
安全性与几个新的和已更改的功能相关
- 多重相等
- 限制隐式转换
- 空安全性
- 安全初始化
人体工程学的良好示例是枚举和扩展方法,它们已以非常可读的方式添加到 Scala 3 中
// enumeration
enum Color:
case Red, Green, Blue
// extension methods
extension (c: Circle)
def circumference: Double = c.radius * math.Pi * 2
def diameter: Double = c.radius * 2
def area: Double = math.Pi * c.radius * c.radius
性能涉及多个领域。其中之一是 不透明类型。在 Scala 2 中,有几次尝试创建解决方案来遵循领域驱动设计 (DDD) 实践,即为值提供更有意义的类型。这些尝试包括
- 类型别名
- 值类
- 案例类
不幸的是,所有这些方法都有弱点,如 不透明类型 SIP 中所述。相反,该 SIP 中所述的不透明类型的目标是“对这些包装器类型的操作在运行时不会产生任何额外开销,同时在编译时仍提供类型安全的使用。”
有关更多类型系统详细信息,请参阅 参考文档。
其他出色的功能
Scala 有许多出色的功能,选择前 10 个列表可能很主观。多项调查显示,不同的开发者群体喜欢不同的功能。希望您在使用该语言时发现更多出色的 Scala 功能。