Scala 3 — 书籍

面向 JavaScript 开发者的 Scala

语言

此页面比较了 JavaScript 和 Scala 编程语言。它面向了解 JavaScript 并希望了解 Scala 的程序员,具体是通过查看 JavaScript 语言功能与 Scala 的比较示例。

概述

本节提供了后续章节的相对简要介绍和总结。它从高层次介绍了 JavaScript 和 Scala 之间的相似性和差异,然后介绍了编写代码时每天都会遇到的差异。

高层次相似性

从高层次来看,Scala 与 JavaScript 具有以下相似性

  • 两者都被认为是高级编程语言,你无需关注指针和手动内存管理等低级概念
  • 两者都有相对简单、简洁的语法
  • 两者都支持 C/C++/Java 风格的大括号语法来编写方法和其他代码块
  • 两者都包含面向对象编程 (OOP) 的功能(如类)
  • 两者都包含(例如 lambda)用于 函数式编程(FP)的功能
  • JavaScript 在浏览器和其他环境(例如 Node.js)中运行。Scala 的 Scala.js 版本针对 JavaScript,因此 Scala 程序可以在相同环境中运行。
  • 开发人员使用 Node.js 用 JavaScript 和 Scala 编写服务器端应用程序;类似于 Play Framework 的项目也允许您用 Scala 编写服务器端应用程序
  • 两种语言都有类似的 if 语句、while 循环和 for 循环
  • 此 Scala.js 页面 开始,您会找到几十个库来支持 React、Angular、jQuery 和许多其他 JavaScript 和 Scala 库
  • JavaScript 对象是可变的;Scala 对象在以命令式风格编写时可以是可变的
  • JavaScript 和 Scala 都支持promise,作为处理异步计算结果的一种方式(Scala 并发使用 future 和 promise)

高级差异

同样在高级别上,JavaScript 和 Scala 之间的一些差异是

  • JavaScript 是动态类型的,而 Scala 是静态类型的
    • 尽管 Scala 是静态类型的,但类型推断等特性使它感觉像一门动态语言(正如您将在以下示例中看到的那样)
  • Scala 惯用语默认支持不可变性:鼓励您使用不可变变量和不可变集合
  • Scala 具有简洁但可读的语法;我们称之为表达式
  • Scala 是一种纯 OOP 语言,因此每个对象都是一个类的实例,类似于 ++= 的符号看起来像运算符,实际上是方法;这意味着您可以创建自己的方法,这些方法作为运算符工作
  • 作为一种纯 OOP 语言和一种纯 FP 语言,Scala 鼓励融合 OOP 和 FP,使用函数进行逻辑处理,使用不可变对象进行模块化
  • Scala 拥有最先进的第三方开源函数式编程库
  • Scala 中的一切都是一个表达式:类似于 if 语句、for 循环、match 表达式,甚至 try/catch 表达式的构造都具有返回值
  • Scala Native 项目允许您编写“系统”级别代码,还可以编译为本机可执行文件

编程级别差异

在较低级别上,这些是您在编写代码时每天都会看到的一些差异

  • Scala 变量和参数使用 val(不可变,类似于 JavaScript const)或 var(可变,类似于 JavaScript varlet)进行定义
  • Scala 不在行尾使用分号
  • Scala 是静态类型的,尽管在许多情况下你不需要声明类型
  • Scala 使用特质作为接口并创建混入
  • 除了简单的 for 循环,Scala 还有强大的 for 推导,它根据你的算法生成结果
  • 模式匹配和 match 表达式将改变你编写代码的方式
  • Scala 的 上下文抽象项推断提供了一系列功能
    • 扩展方法 允许你向封闭类添加新功能,而不会破坏模块化,因为它们仅在特定作用域中可用(与猴子补丁不同,猴子补丁会污染代码的其他区域)
    • 给定的实例 允许你定义编译器可用于为你合成代码的项
    • 类型安全和 多重相等性 允许你在编译时将相等性比较限制为仅有意义的比较
  • 借助按名称参数、中缀表示法、可选括号、扩展方法和 高阶函数 等特性,你可以创建自己的“控制结构”和 DSL
  • 本书中你可以阅读到的许多其他优点:case 类、伴随类和对象、宏、并集交集 类型、多个参数列表、命名参数等

变量和类型

注释

//
/* ... */
/** ... */
//
/* ... */
/** ... */

可变变量

let   // 现在首选用于可变
var   // 旧的可变样式
var  // 用于可变变量

不可变值

const
val

Scala 中的经验法则是使用 val 声明变量,除非你有特定原因需要可变变量。

命名标准

JavaScript 和 Scala 通常使用相同的驼峰式命名标准。变量命名为 myVariableName,方法命名为 lastIndexOf,类和对象命名为 AnimalPrintedBook

字符串

字符串的许多用法在 JavaScript 和 Scala 中是相似的,尽管 Scala 仅对简单字符串使用双引号,对多行字符串使用三引号。

字符串基础

// 使用单引号或双引号
let msg = 'Hello, world';
let msg = "Hello, world";
// 仅使用双引号
val msg = "Hello, world"

插值

let name = 'Joe';

// JavaScript 使用反引号
let msg = `Hello, ${name}`;
val name = "Joe"
val age = 42
val weight = 180.5

// 在字符串前使用 `s` 进行简单插值
println(s"Hi, $name")   // "Hi, Joe"
println(s"${1 + 1}")    // "2"

// 在字符串前使用 `f` 允许使用 printf 风格的格式化。
// 此示例打印
// "Joe is 42 years old, and weighs"
// "180.5 pounds."
println(f"$name is $age years old, and weighs $weight%.1f pounds.")

带插值的多分行字符串

let name = "joe";
let str = `
Hello, ${name}.
This is a multiline string.
`;
val name = "Martin Odersky"

val quote = s"""
|$name says
|Scala is a fusion of
|OOP and FP.
""".stripMargin.replaceAll("\n", " ").trim

// 结果
// "Martin Odersky says Scala is a fusion of OOP and FP."

JavaScript 和 Scala 还有类似的方法来处理字符串,包括 charAtconcatindexOf 以及更多方法。转义字符(如 \n\f\t)在这两种语言中也是相同的。

数字和算术

JavaScript 和 Scala 的数字运算符类似。最大的不同之处在于 Scala 不提供 ++-- 运算符。

数字运算符

let x = 1;
let y = 2.0;
 
let a = 1 + 1;
let b = 2 - 1;
let c = 2 * 2;
let d = 4 / 2;
let e = 5 % 2;
val x = 1
val y = 2.0
 
val a = 1 + 1
val b = 2 - 1
val c = 2 * 2
val d = 4 / 2
val e = 5 % 2

增量和减量

i++;
i += 1;

i--;
i -= 1;
i += 1;
i -= 1;

也许最大的区别是,像 +- 这样的“运算符”在 Scala 中实际上是方法,而不是运算符。Scala 数字还具有这些相关方法

var a = 2
a *= 2      // 4
a /= 2      // 2

Scala 的 Double 类型最接近 JavaScript 的默认 number 类型,Int 表示带符号的 32 位整数值,BigInt 对应于 JavaScript 的 bigint

这些是 Scala IntDouble 值。请注意,不必显式声明类型

val i = 1     // Int
val d = 1.1   // Double

您还可以根据需要使用其他数字类型

val a: Byte = 0    // Byte = 0
val a: Double = 0  // Double = 0.0
val a: Float = 0   // Float = 0.0
val a: Int = 0     // Int = 0
val a: Long = 0    // Long = 0
val a: Short = 0   // Short = 0

val x = BigInt(1_234_456_789)
val y = BigDecimal(1_234_456.890)

布尔值

两种语言都使用 truefalse 表示布尔值

let a = true;
let b = false;
val a = true
val b = false

日期

日期是两种语言中另一个常用的类型。

获取当前日期

let d = new Date();

// 结果
// Sun Nov 29 2020 18:47:57 GMT-0700 (Mountain Standard Time)
// 获取当前日期和时间的方法不同
import java.time.*

val a = LocalDate.now
    // 2020-11-29
val b = LocalTime.now
    // 18:46:38.563737
val c = LocalDateTime.now
    // 2020-11-29T18:46:38.563750
val d = Instant.now
    // 2020-11-30T01:46:38.563759Z

指定不同的日期

let d = Date(2020, 1, 21, 1, 0, 0, 0);
let d = Date(2020, 1, 21, 1, 0, 0);
let d = Date(2020, 1, 21, 1, 0);
let d = Date(2020, 1, 21, 1);
let d = Date(2020, 1, 21);
val d = LocalDate.of(2020, 1, 21)
val d = LocalDate.of(2020, Month.JANUARY, 21)
val d = LocalDate.of(2020, 1, 1).plusDays(20)

在这种情况下,Scala 使用 Java 附带的日期和时间类。JavaScript 和 Scala 之间有很多日期/时间方法相似。有关更多详细信息,请参阅 java.time

函数

在 JavaScript 和 Scala 中,函数都是对象,因此它们的功能相似,但语法和术语略有不同。

命名函数,一行

function add(a, b) {
  return a + b;
}
add(2, 2);   // 4
// 从技术上讲,这是一个方法,而不是一个函数
def add(a: Int, b: Int) = a + b
add(2, 2)   // 4

命名函数,多行

function addAndDouble(a, b) {
  // 想象一下,这需要
  // 多行
  return (a + b) * 2
}
def addAndDouble(a: Int, b: Int): Int =
  // 想象一下,这需要
  // 多行
  (a + b) * 2

在 Scala 中,显示 Int 返回类型是可选的。在 add 示例中显示,而在 addAndDouble 示例中显示,因此你可以看到两种方法。

匿名函数

JavaScript 和 Scala 都允许你定义匿名函数,你可以将它们传递到其他函数和方法中。

箭头和匿名函数

// 箭头函数
let log = (s) => console.log(s)

// 匿名函数
let log = function(s) {
  console.log(s);
}

// 在这里使用这两个函数中的任何一个
function printA(a, log) {
  log(a);
}
// 一个函数(一个分配给变量的匿名函数)
val log = (s: String) => console.log(s)

// 一个 scala 方法。方法往往更常使用,
// 可能因为它们更容易阅读。
def log(a: Any) = console.log(a)

// 一个函数或一个方法可以传递到另一个
// 函数或方法
def printA(a: Any, f: log: Any => Unit) = log(a)

在 Scala 中,你很少使用显示的第一个语法定义函数。相反,你通常在使用点直接定义匿名函数。许多集合方法是 高阶函数,并接受函数参数,因此你可以编写这样的代码

// map method, long form
List(1,2,3).map(i => i * 10)   // List(10,20,30)

// map, short form (which is more commonly used)
List(1,2,3).map(_ * 10)        // List(10,20,30)

// filter, short form
List(1,2,3).filter(_ < 3)      // List(1,2)

// filter and then map
List(1,2,3,4,5).filter(_ < 3).map(_ * 10)   // List(10, 20)

Scala 既有类也有 case 类。类似于 JavaScript 类,通常用于 OOP 样式应用程序(尽管它们也可以用于 FP 代码),而 case 类具有其他功能,使其在 FP 样式应用程序 中非常有用。

以下示例展示了如何将几种类型创建为枚举,然后定义 OOP 样式 Pizza 类。最后,创建并使用了一个 Pizza 实例

// create some enumerations that the Pizza class will use
enum CrustSize:
  case Small, Medium, Large

enum CrustType:
  case Thin, Thick, Regular

enum Topping:
  case Cheese, Pepperoni, BlackOlives, GreenOlives, Onions

// import those enumerations and the ArrayBuffer,
// so the Pizza class can use them
import CrustSize.*
import CrustType.*
import Topping.*
import scala.collection.mutable.ArrayBuffer

// define an OOP style Pizza class
class Pizza(
  var crustSize: CrustSize,
  var crustType: CrustType
):

  private val toppings = ArrayBuffer[Topping]()

  def addTopping(t: Topping): Unit =
    toppings += t

  def removeTopping(t: Topping): Unit =
    toppings -= t

  def removeAllToppings(): Unit =
    toppings.clear()

  override def toString(): String =
    s"""
      |Pizza:
      |  Crust Size: ${crustSize}
      |  Crust Type: ${crustType}
      |  Toppings:   ${toppings}
    """.stripMargin

end Pizza

// create a Pizza instance
val p = Pizza(Small, Thin)

// change the crust
p.crustSize = Large
p.crustType = Thick

// add and remove toppings
p.addTopping(Cheese)
p.addTopping(Pepperoni)
p.addTopping(BlackOlives)
p.removeTopping(Pepperoni)

// print the pizza, which uses its `toString` method
println(p)

接口、特征和继承

Scala 使用特征作为接口,也用于创建 mixin。特征既可以有抽象成员,也可以有具体成员,包括方法和字段。

此示例展示了如何定义两个特征,创建一个扩展并实现这些特征的类,然后创建并使用该类的实例

trait HasLegs:
  def numLegs: Int
  def walk(): Unit
  def stop() = println("Stopped walking")

trait HasTail:
  def wagTail(): Unit
  def stopTail(): Unit

class Dog(var name: String) extends HasLegs, HasTail:
  val numLegs = 4
  def walk() = println("I’m walking")
  def wagTail() = println("⎞⎜⎛  ⎞⎜⎛")
  def stopTail() = println("Tail is stopped")
  override def toString = s"$name is a Dog"

// create a Dog instance
val d = Dog("Rover")

// use the class’s attributes and behaviors
println(d.numLegs)   // 4
d.wagTail()          // "⎞⎜⎛  ⎞⎜⎛"
d.walk()             // "I’m walking"

控制结构

除了 JavaScript 中使用 ===!== 之外,比较和逻辑运算符在 JavaScript 和 Scala 中几乎完全相同。

比较运算符

JavaScript Scala
== ==
=== ==
!= !=
!== !=
> >
< <
>= >=
<= <=

逻辑运算符

JavaScript Scala
&&
||
!
&&
||
!

if/then/else 表达式

JavaScript 和 Scala 的 if/then/else 语句类似。在 Scala 2 中,它们几乎完全相同,但在 Scala 3 中,不再需要大括号(尽管仍然可以使用)。

if 语句,一行

if (x == 1) { console.log(1); }
if x == 1 then println(x)

if 语句,多行

if (x == 1) {
  console.log("x is 1, as you can see:")
  console.log(x)
}
if x == 1 then
  println("x is 1, as you can see:")
  println(x)

if、else if、else

if (x < 0) {
  console.log("negative")
} else if (x == 0) {
  console.log("zero")
} else {
  console.log("positive")
}
if x < 0 then
  println("negative")
else if x == 0
  println("zero")
else
  println("positive")

if 返回值

JavaScript 使用三元运算符,而 Scala 照常使用其 if 表达式

让 minVal = a < b ? a : b;
val minValue = 如果 a < b 则 a 否则 b

if 作为方法的主体

Scala 方法往往很短,你可以轻松地使用 if 作为方法的主体

函数 min(a, b) {
  返回 (a < b) ? a : b;
}
def min(a: Int, b: Int): Int =
 如果 a < b 则 a 否则 b

在 Scala 3 中,如果你愿意,你仍然可以使用“大括号”样式。例如,你可以像这样写一个 if/else-if/else 表达式

if (i == 0) {
  println(0)
} else if (i == 1) {
  println(1)
} else {
  println("other")
}

循环

JavaScript 和 Scala 都有 while 循环和 for 循环。Scala 曾经有 do/while 循环,但它们已从语言中删除。

while 循环

让 i = 0;
while (i < 3) {
  控制台.log(i);
  i++;
}
var i = 0;
while i < 3 do
  println(i)
  i += 1

如果你愿意,Scala 代码也可以这样写

var i = 0
while (i < 3) {
  println(i)
  i += 1
}

以下示例展示了 JavaScript 和 Scala 中的 for 循环。它们假设你有这些集合可以使用

// JavaScript
let nums = [1, 2, 3];

// Scala
val nums = List(1, 2, 3)

for 循环,单行

// 较新的语法
对于 (let i of nums) {
  控制台.log(i);
}

// 较旧的
对于 (i=0; i<nums.length; i++) {
  控制台.log(nums[i]);
}
// 优先
对于 i <- ints do println(i)

// 也可用
对于 (i <- ints) println(i)

for 循环,主体中有多行

// 优先
对于 (let i of nums) {
  让 j = i * 2;
  控制台.log(j);
}

// 也可用
对于 (i=0; i<nums.length; i++) {
  让 j = nums[i] * 2;
  控制台.log(j);
}
// 优先
对于 i <- ints do
  val i = i * 2
  println(j)

// 也可用
对于 (i <- nums) {
  val j = i * 2
  println(j)
}

for 循环中的多个生成器

让 str = "ab";
对于 (let i = 1; i < 3; i++) {
  对于 (var j = 0; j < str.length; j++) {
    for (let k = 1; k < 11; k++) {
      let c = str.charAt(j);
      console.log(`i: ${i} j: ${c} k: ${k}`);
    }
  }
}
for
  i <- 1 to 2
  j <- 'a' to 'b'
  k <- 1 to 10 by 5
do
  println(s"i: $i, j: $j, k: $k")

带守卫的生成器

守卫for 表达式中 if 表达式的名称。

for (let i = 0; i < 10; i++) {
  if (i % 2 == 0 && i < 5) {
    console.log(i);
  }
}
for
  i <- 1 to 10
  if i % 2 == 0
  if i < 5
do
  println(i)

for 推导

for 推导是一种 for 循环,它使用 yield 返回(生成)一个值。它们在 Scala 中经常使用。

不适用
val list =
  for
    i <- 1 to 3
  yield
    i * 10
// result: Vector(10, 20, 30)

switch 和 match

JavaScript 有 switch 语句,而 Scala 有 match 表达式。与 Scala 中的其他所有内容一样,它们实际上是表达式,这意味着它们返回一个结果

val day = 1

// later in the code ...
val monthAsString = day match
  case 1 => "January"
  case 2 => "February"
  case _ => "Other"

match 表达式可以在每个 case 语句中处理多个匹配项

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 isPerson(x: Matchable): Boolean = x match
  case p: Person => true
  case _ => false

match 表达式还有许多其他模式匹配选项。

集合类

Scala 针对不同的需求提供了不同的 集合类

常见的不可变序列是

  • List
  • Vector

常见的可变序列是

  • Array
  • ArrayBuffer

Scala 还有可变和不可变的 Maps 和 Sets。

以下是创建常见的 Scala 集合类型的方法

val strings = List("a", "b", "c")
val strings = Vector("a", "b", "c")
val strings = ArrayBuffer("a", "b", "c")

val set = Set("a", "b", "a") // result: Set("a", "b")
val map = Map(
  "a" -> 1,
  "b" -> 2,
  "c" -> 3
)

集合上的方法

以下示例展示了使用 Scala 集合的多种不同方法。

填充列表

// to, until
(1 to 5).toList                   // List(1, 2, 3, 4, 5)
(1 until 5).toList                // List(1, 2, 3, 4)

(1 to 10 by 2).toList             // List(1, 3, 5, 7, 9)
(1 until 10 by 2).toList          // List(1, 3, 5, 7, 9)
(1 to 10).by(2).toList            // List(1, 3, 5, 7, 9)

('d' to 'h').toList               // List(d, e, f, g, h)
('d' until 'h').toList            // List(d, e, f, g)
('a' to 'f').by(2).toList         // List(a, c, e)

// range method
List.range(1, 3)                  // List(1, 2)
List.range(1, 6, 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)

序列上的函数方法

// these examples use a List, but they’re the same with Vector
val a = List(10, 20, 30, 40, 10)      // List(10, 20, 30, 40, 10)
a.contains(20)                        // true
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.last                                // 10
a.lastOption                          // Some(10)
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)

// map, flatMap
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)

List(1,2,3).updated(0,10)             // List(10, 2, 3)
List(2,4).union(List(1,3))            // List(2, 4, 1, 3)

// zip
val women = List("Wilma", "Betty")    // List(Wilma, Betty)
val men = List("Fred", "Barney")      // List(Fred, Barney)
val couples = women.zip(men)          // List((Wilma,Fred), (Betty,Barney))

Scala 有更多方法供你使用。所有这些方法的好处是

  • 你不必编写自定义 for 循环来解决问题
  • 当你阅读其他人的代码时,你不必阅读他们的自定义 for 循环;你只需找到像这些一样的通用方法,这样可以更轻松地阅读来自不同项目的代码

元组

当你想在同一个列表中放置多种数据类型时,JavaScript 允许你这样做

let stuff = ["Joe", 42, 1.0];

在 Scala 中,你可以这样做

val a = ("eleven")
val b = ("eleven", 11)
val c = ("eleven", 11, 11.0)
val d = ("eleven", 11, 11.0, Person("Eleven"))

在 Scala 中,这些类型称为元组,并且如所示,它们可以包含一个或多个元素,并且元素可以具有不同的类型。你可以像访问 ListVectorArray 的元素一样访问它们的元素

d(0)   // "eleven"
d(1)   // 11

枚举

JavaScript 没有枚举,但你可以这样做

let Color = {
  RED: 1,
  GREEN: 2,
  BLUE: 3
};
Object.freeze(Color);

在 Scala 3 中,你可以使用枚举做很多事情。你可以创建等效的代码

enum Color:
  case Red, Green, Blue

你可以创建参数化枚举

enum Color(val rgb: Int):
  case Red   extends Color(0xFF0000)
  case Green extends Color(0x00FF00)
  case Blue  extends Color(0x0000FF)

你还可以创建用户定义的枚举成员

enum Planet(mass: Double, radius: Double):
  case Mercury extends Planet(3.303e+23, 2.4397e6)
  case Venus   extends Planet(4.869e+24,6.0518e6)
  case Earth   extends Planet(5.976e+24,6.37814e6)
  // more planets here ...

  private final val G = 6.67300E-11
  def surfaceGravity = G * mass / (radius * radius)
  def surfaceWeight(otherMass: Double) = otherMass * surfaceGravity

Scala.js DOM 代码

Scala.js 允许你编写编译为 JavaScript 代码的 Scala 代码,然后可以在浏览器中使用该代码。该方法类似于 TypeScript、ReScript 和编译为 JavaScript 的其他语言。

在你包含必要的库并在项目中导入必要的包后,编写 Scala.js 代码看起来与编写 JavaScript 代码非常相似

// show an alert dialog on a button click
jQuery("#hello-button").click{() =>
  dom.window.alert("Hello, world")
}

// define a button and what should happen when it’s clicked
val btn = button(
  "Click me",
  onclick := { () =>
    dom.window.alert("Hello, world")
  })

// create two divs with css classes, an h2 element, and the button
val content =
  div(cls := "foo",
    div(cls := "bar",
      h2("Hello"),
      btn
    )
  )

// add the content to the DOM
val root = dom.document.getElementById("root")
root.innerHTML = ""
root.appendChild(content.render)

请注意,尽管 Scala 是一种类型安全语言,但上述代码中未声明任何类型。Scala 的强大类型推断功能通常使 Scala 代码看起来像是动态类型。但它是类型安全的,因此你可以在开发周期的早期发现许多类错误。

其他 Scala.js 资源

Scala.js 网站为有兴趣使用 Scala.js 的 JavaScript 开发人员提供了大量出色的教程。以下是他们的一些初始教程

Scala 独有的概念

Scala 中还有其他概念,目前在 JavaScript 中没有等效的概念

  • 几乎所有与 上下文抽象 相关的内容
  • 方法特性
    • 多参数列表
    • 在调用方法时使用命名参数
  • 将特质用作接口
  • 案例类
  • 伴生类和对象
  • 创建自己的 控制结构 和 DSL 的能力
  • match 表达式和模式匹配的高级特性
  • for 推导
  • 中缀方法
  • 宏和元编程
  • 更多 …

本页面的贡献者