为何选择 Scala 3?

使用 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 被定义为一个类,从技术上讲它是一个抽象类,并且可以像这样创建一个新实例
Scala 2 和 3
val x = List(1, 2, 3)
然而,对程序员来说,一个简单的 List 实际上是由几种专门类型的组合构建的,包括名为 Iterable、Seq 和 LinearSeq 的特质。这些类型同样由其他小型模块化代码单元组成。
除了从一系列模块化特质构建 List 这样的类型之外,List API 还包含几十个其他方法,其中许多是高阶函数
Scala 2 和 3
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 的类型推断通常会让语言感觉是动态类型的,即使它是静态类型的。变量声明就是如此
Scala 2 和 3
val a = 1
val b = "Hello, world"
val c = List(1,2,3,4,5)
val stuff = ("fish", 42, 1_234.5)
将匿名函数传递给高阶函数时也是如此
Scala 2 和 3
list.filter(_ < 4)
list.map(_ * 2)
list.filter(_ < 4)
.map(_ * 2)
以及定义方法时
Scala 2 和 3
def add(a: Int, b: Int) = a + b
在 Scala 3 中,这种情况比以往任何时候都更加明显,例如使用联合类型时
仅限 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 是一种低仪式,“简洁但仍然可读”的语言。例如,变量声明很简洁
Scala 2 和 3
val a = 1
val b = "Hello, world"
val c = List(1,2,3)
创建特质、类和枚举等类型很简洁
仅限 Scala 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
)
高阶函数很简洁
Scala 2 和 3
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 本质上是一个 Java String,其中添加了其他功能
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。
以下是一些示例
Scala 2 和 3
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 声明
Scala 2 和 3
val a = 1 // immutable variable
你还应该使用不可变集合类,如 List 和 Map
Scala 2 和 3
val b = List(1,2,3) // List is immutable
val c = Map(1 -> "one") // Map is immutable
用例类主要用于领域建模,并且其参数是不可变的
Scala 2 和 3
case class Person(name: String)
val p = Person("Michael Scott")
p.name // Michael Scott
p.name = "Joe" // compiler error (reassignment to val name)
如前一节所示,Scala 集合类支持高阶函数,你可以将方法(未显示)和匿名函数传递给它们
Scala 2 和 3
a.dropWhile(_ < 25)
a.filter(_ < 25)
a.takeWhile(_ < 30)
a.filter(_ < 30).map(_ * 10)
nums.sortWith(_ < _)
nums.sortWith(_ > _)
match 表达式让你能够使用模式匹配,它们真正是返回值的表达式
Scala 2
Scala 3
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"
由于它们可以返回值,因此它们通常用作方法的主体
Scala 2
Scala 3
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 中
仅限 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 功能。