表达力强
Scala 允许您用更少的代码做更多的事情。作为一种高级语言,其现代功能提高了生产力并使代码更易读。使用 Scala,您可以结合函数式和面向对象编程风格来帮助构建程序。
可扩展
Scala 非常适合使用其 JVM、JavaScript 和 Native 运行时构建快速、并发和分布式系统。Scala 优先考虑互操作性,可以轻松访问许多行业验证库的生态系统。
安全
Scala 的静态类型默认情况下有助于您构建安全的系统。智能的内置检查和可操作的错误消息,再加上线程安全的數據结构和集合,可以防止程序首次运行之前出现许多棘手的错误。
已验证的用例
世界各地的人们都信任 Scala 来构建有用的软件。流行的领域包括
服务器端
高吞吐量 HTTP 服务器和客户端。安全、可扩展和原则性的并发。使用强大的转换进行可靠的数据验证。
原则性并发
Scala 的表达能力和编译器强制的安全机制使构建可靠的并发代码变得更容易。
使用 Scala,您的程序可以充分利用多核和分布式架构,确保对资源的安全访问,并根据您的处理速度对数据生产者施加背压。
在 Scala 中管理并发的流行开源选项之一是 Cats Effect,与 http4s 结合使用来定义服务器和路由。点击下方查看其他解决方案。
并发和分布式库// HTTP server routing definition
val service = HttpRoutes.of:
case GET -> Root / "weather" => // route '/weather'
for
winner <- fetch1.race(fetch2).timeout(10.seconds)
response <- Ok(WeatherReport.from(winner))
yield
response
def fetch1 = fetchWeather(server1) // expensive Network IO
def fetch2 = fetchWeather(server2) // expensive Network IO
成熟的库生态系统
使用 Scala 的最佳功能,或利用来自 Java 和 JavaScript 生态系统的库。
使用单体或微服务架构构建。保留资源效率。将您的数据持久化到任何类型的数据库。将数据转换为任何格式(JSON、protobuf、Parquet 等),并进行验证和序列化。
无论您是为 Node.js 还是 Java 平台编译,Scala 与两者的互操作性都让您可以访问更多经过广泛验证的库。
为您的下一个 Scala 项目找到合适的库def Device(lastTemp: Option[Double]): Behavior[Message] =
Behaviors.receiveMessage:
case RecordTemperature(id, value, replyTo) =>
replyTo ! TemperatureRecorded(id)
Device(lastTemp = Some(value))
case ReadTemperature(id, replyTo) =>
replyTo ! RespondTemperature(id, lastTemp)
Behaviors.same
案例研究:使用 Tapir 重用代码
利用“代码即数据”范式:定义一次,随处使用。
Scala 丰富的类型系统和元编程功能赋予了从代码中自动推导出有用工具的能力。
一个这样的示例库是 Tapir,它允许您使用 Scala 作为声明式语言来描述您的 HTTP 端点。从这个单一的事实来源,您可以自动推导出它们的服务器实现、客户端实现以及人类可读和机器可读的文档。
由于一切都源于类型安全的定义,端点调用在编译时在前端和后端之间得到安全检查。
在 Tapir 文档中了解更多信息// type-safe endpoint definition
val reportEndpoint =
endpoint
.in("api" / "report" / path[String]("reportId"))
.out(jsonBody[Report])
// derived Docs, Server and Client
val apiDocs = docsReader
.toOpenAPI(reportEndpoint, "Fetch Report", "1.0.0")
val server = serverBuilder(port = "8080")
.addEndpoint(reportEndpoint.handle(fetchReport))
.start()
val client = clientReader
.toRequest(reportEndpoint, "http://localhost:8080")
val report: Future[Report] =
client("5ca1a-78fc8d6") // call like any function
数据处理
选择您最喜欢的笔记本。运行大规模分布式大数据管道;训练 NLP 或 ML 模型;执行数值分析;可视化数据等等。
// Count the number of words in a text source
val textFile = spark.textFile("hdfs://...")
val counts = textFile
.flatMap(line => line.split(" "))
.map(word => (word, 1))
.reduceByKey(_ + _)
counts.saveAsTextFile("hdfs://...")
笔记本
在基于 Web 的笔记本中探索数据并生成丰富、交互式的输出。
将代码、数据和可视化内容组合在一个文档中。进行更改并立即查看结果。与他人共享和协作。
除了许多云托管解决方案之外,Scala 的开源笔记本还包括 almond Jupyter 内核、Zeppelin 和 Polynote。
用于大数据和可视化的库命令行
使用 Scala 命令增强您的脚本。亲身体验 Scala 工具包。轻松添加库。使用即时启动构建 CLI 应用程序。
一个文件中 Scala 的强大功能
Scala CLI 提供了创建简单 Scala 项目所需的所有工具。
导入您喜欢的库,编写代码,运行它,创建单元测试,将其作为 gist 共享,或将其发布到 Maven Central。
Scala CLI 速度快,配置低,适用于 IDE,并遵循众所周知的约定。
在 Scala CLI 网站上了解更多信息//> using dependency com.lihaoyi::os-lib:0.9.1
// Sort all the files by size in the working directory
os.list(os.pwd).sortBy(os.size).foreach(println)
$ scala-cli list_files.sc
/home/user/example/list_files.sc
...
使用 Scala 工具包提高工作效率
Scala 工具包非常适合编写脚本、原型设计或引导新的应用程序。
Scala 工具包包含一系列易于使用的库来执行日常任务,可帮助您处理文件和进程、解析 JSON、发送 HTTP 请求和进行单元测试代码。
工具包库在 JVM、JS 和 Native 平台上运行良好,同时利用简单的代码风格。
在工具包教程中查找有用的代码片段//> using toolkit latest
// A JSON object
val json = ujson.Obj("name" -> "Peter", "age" -> 23)
// Send an HTTP request
import sttp.client4.quick.*
val response = quickRequest
.put(uri"https://httpbin.org/put")
.body(ujson.write(json))
.send()
// Write the response to a file
os.write(os.pwd / "response.json", response.body)
$ scala-cli --power package \
--native-image \
--output my-tool \
my-tool.sc
Wrote /home/user/example/my-tool, run it with ./my-tool
前端 Web
由类型支持的响应式 UI。在整个堆栈中使用相同的 Scala 库。与 JavaScript 库和工具生态系统集成。
可移植代码和库
编写一次代码,使其在前端和后端都能运行。
在两端重用相同的库和测试框架。编写跨堆栈类型检查的 API 端点。
例如:在共享模块中定义您的数据模型。然后使用 sttp 将数据发送到后端,同时 upickle 处理与 JSON 的无缝转换,并在后端将 JSON 读取回您的模型。
更多 Scala.js 库和框架enum Pet derives upickle.ReadWriter:
case Dog(id: UUID, name: String, owner: String)
case Cat(id: UUID, name: String, owner: String)
// Send an HTTP request to the backend with sttp
val dog = Dog(uuid, name, owner)
val response = quickRequest
.patch(uri"${site.root}/petstore/$uuid")
.body(dog)
.send()
response.onComplete { resp => println(s"updated $dog") }
与 JavaScript 的互操作性
从 npm 生态系统中的 JS 库调用,或将您的 Scala.js 代码导出到其他 JS 模块。与 Vite 集成以实现即时实时重新加载。
利用 JavaScript 库生态系统。使用 ScalablyTyped 从 TypeScript 定义生成 JavaScript 库的类型。
流行 JavaScript 库的 Scala.js 外观val Counter = FunctionalComponent[Int] { initial =>
val (count, setCount) = useState(initial)
button(onClick := { event => setCount(count + 1) },
s"You pressed me ${count} times"
)
}
ReactDOM.render(Counter(0), mountNode)
强大的用户界面库
使用 Scala.js UI 库编写健壮的 UI。
选择您喜欢的风格:Laminar 用于纯 Scala 解决方案,Slinky 用于 React 体验,或 Tyrian 或 scalajs-react 用于纯 FP 思想的开发人员。
查看更多用于前端和 UI 的 Scala.js 库def view(count: Int): Html[Msg] =
button(onClick(Msg.Increment))(
s"You pressed me ${count} times"
)
def update(count: Int): Update[Msg, Int] =
case Msg.Increment => (count + 1, Cmd.None)
case _ => (count, Cmd.None)
还有其他用例吗?Scaladex 索引了很棒的 Scala 库。在下面的框中搜索。
非常适合教学
Scala 非常适合教授编程入门课程,以及教授高级软件工程课程。
可读且用途广泛
软件设计中涉及的大多数概念都直接映射到 Scala 结构。Scala 简洁的语法允许教师和学习者专注于这些有趣的概念,而无需处理繁琐的底层实现问题。
以下 HelloWorld.scala
文件中的示例展示了 Scala 中的“hello world”程序。在 Modeling.scala
中,我们展示了在 Scala 中构建问题域信息的示例。在 Modules.scala
中,我们展示了使用 Scala 类实现软件模块的简单性。最后,在 Algorithms.scala
中,我们展示了如何利用标准 Scala 集合来用几行代码实现算法。
在关于 教学 的专用页面中了解更多信息。
@main def run() = println("Hello, World!")
// Average number of contacts a person has according to age
def contactsByAge(people: Seq[Person]): Map[Int, Double] =
people
.groupMap(
person => person.age
)(
person => person.contacts.size
)
.map((age, contactCounts) =>
val averageContactCount =
contactCounts.sum.toDouble / contactCounts.size
(age, averageContactCount)
)
/** A Player can either be a Bot, or a Human.
* In case it is a Human, it has a name.
*/
enum Player:
case Bot
case Human(name: String)
// A module that can access the data stored in a database
class DatabaseAccess(connection: Connection):
def readData(): Seq[Data] = ???
// An HTTP server, which uses the `DatabaseAccess` module
class HttpServer(databaseAccess: DatabaseAccess):
// The HTTP server can call `readData`, but it cannot
// access the underlying database connection, which is
// an implementation detail
databaseAccess.readData()