在本页面中,我们将介绍 Scala 的基础知识。
在浏览器中尝试 Scala
您可以使用 Scastie 在浏览器中运行 Scala。这是一种简单、无需设置的方式来试验 Scala 代码片段
- 转到 Scastie。
- 在左窗格中粘贴
println("Hello, world!")
。 - 单击运行。输出将显示在右窗格中。
Scastie 与本文档中的一些代码示例集成在一起;如果您在下面的代码示例中看到运行按钮,请单击该按钮直接试验代码。
表达式
表达式是可以计算的语句
1 + 1
您可以使用 println
输出表达式的结果
println(1) // 1
println(1 + 1) // 2
println("Hello!") // Hello!
println("Hello," + " world!") // Hello, world!
值
您可以使用 val
关键字来命名表达式的结果
val x = 1 + 1
println(x) // 2
命名的结果(如这里的 x
)称为值。引用值不会重新计算它。
值无法重新分配
x = 3 // This does not compile.
值的类型可以省略并 推断,也可以明确声明
val x: Int = 1 + 1
请注意类型声明 Int
如何位于标识符 x
之后。您还需要一个 :
。
变量
变量类似于值,但您可以重新分配它们。您可以使用 var
关键字定义变量。
var x = 1 + 1
x = 3 // This compiles because "x" is declared with the "var" keyword.
println(x * x) // 9
与值一样,变量的类型可以省略并推断,也可以明确声明
var x: Int = 1 + 1
块
你可以通过用 {}
包围表达式来组合它们。我们称之为块。
块中最后一个表达式的结果也是整个块的结果
println({
val x = 1 + 1
x + 1
}) // 3
函数
函数是有参数并接受参数的表达式。
你可以定义一个匿名函数(即没有名称的函数),它返回给定的整数加一
(x: Int) => x + 1
在 =>
的左侧是参数列表。右侧是涉及参数的表达式。
你也可以命名函数
val addOne = (x: Int) => x + 1
println(addOne(1)) // 2
一个函数可以有多个参数
val add = (x: Int, y: Int) => x + y
println(add(1, 2)) // 3
或者它根本没有参数
val getTheAnswer = () => 42
println(getTheAnswer()) // 42
方法
方法的外观和行为与函数非常相似,但它们之间有一些关键的区别。
方法使用 def
关键字定义。 def
后面跟着一个名称、参数列表、一个返回类型和一个主体
def add(x: Int, y: Int): Int = x + y
println(add(1, 2)) // 3
请注意,返回类型 Int
是在参数列表和 :
之后声明的。
一个方法可以采用多个参数列表
def addThenMultiply(x: Int, y: Int)(multiplier: Int): Int = (x + y) * multiplier
println(addThenMultiply(1, 2)(3)) // 9
或者根本没有参数列表
def name: String = System.getProperty("user.name")
println("Hello, " + name + "!")
还有一些其他区别,但现在,你可以将方法视为类似于函数的东西。
方法也可以有多行表达式
def getSquareString(input: Double): String = {
val square = input * input
square.toString
}
println(getSquareString(2.5)) // 6.25
def getSquareString(input: Double): String =
val square = input * input
square.toString
println(getSquareString(2.5)) // 6.25
主体中的最后一个表达式是方法的返回值。(Scala 确实有一个 return
关键字,但它很少使用。)
类
你可以使用 class
关键字定义类,后面跟着它的名称和构造函数参数
class Greeter(prefix: String, suffix: String) {
def greet(name: String): Unit =
println(prefix + name + suffix)
}
class Greeter(prefix: String, suffix: String):
def greet(name: String): Unit =
println(prefix + name + suffix)
方法 greet
的返回类型是 Unit
,表示没有有意义的东西可以返回。它与 Java 和 C 中的 void
类似。(不同之处在于,由于每个 Scala 表达式都必须具有一些值,因此实际上有一个类型为 Unit 的单例值,写为 ()。它不携带任何信息。)
在 Scala 2 中,你可以使用 new
关键字实例化一个类。然而,在 Scala 3 中,由于通用应用方法,不需要 new
关键字
val greeter = new Greeter("Hello, ", "!")
greeter.greet("Scala developer") // Hello, Scala developer!
val greeter = Greeter("Hello, ", "!")
greeter.greet("Scala developer") // Hello, Scala developer!
我们将在稍后深入介绍类。
案例类
Scala 有一种特殊类型的类,称为“案例”类。默认情况下,案例类的实例是不可变的,并且它们通过值进行比较(与通过引用比较其实例的类不同)。这使得它们对于 模式匹配 更加有用。
你可以使用 case class
关键字定义案例类
case class Point(x: Int, y: Int)
你可以在没有 new
关键字的情况下实例化案例类
val point = Point(1, 2)
val anotherPoint = Point(1, 2)
val yetAnotherPoint = Point(2, 2)
案例类的实例通过值进行比较,而不是通过引用
if (point == anotherPoint) {
println(s"$point and $anotherPoint are the same.")
} else {
println(s"$point and $anotherPoint are different.")
} // Point(1,2) and Point(1,2) are the same.
if (point == yetAnotherPoint) {
println(s"$point and $yetAnotherPoint are the same.")
} else {
println(s"$point and $yetAnotherPoint are different.")
} // Point(1,2) and Point(2,2) are different.
if point == anotherPoint then
println(s"$point and $anotherPoint are the same.")
else
println(s"$point and $anotherPoint are different.")
// ==> Point(1,2) and Point(1,2) are the same.
if point == yetAnotherPoint then
println(s"$point and $yetAnotherPoint are the same.")
else
println(s"$point and $yetAnotherPoint are different.")
// ==> Point(1,2) and Point(2,2) are different.
还有更多关于案例类的内容我们想要介绍,我们相信你会爱上它们!我们将在 稍后 深入介绍它们。
对象
对象是其自身定义的单个实例。你可以将它们视为其自身类的单例。
你可以使用 object
关键字定义对象
object IdFactory {
private var counter = 0
def create(): Int = {
counter += 1
counter
}
}
object IdFactory:
private var counter = 0
def create(): Int =
counter += 1
counter
你可以通过引用其名称来访问对象
val newId: Int = IdFactory.create()
println(newId) // 1
val newerId: Int = IdFactory.create()
println(newerId) // 2
我们将在 稍后 深入介绍对象。
特质
特质是包含某些字段和方法的抽象数据类型。在 Scala 继承中,一个类只能扩展另一个类,但它可以扩展多个特质。
你可以使用 trait
关键字定义特质
trait Greeter {
def greet(name: String): Unit
}
trait Greeter:
def greet(name: String): Unit
特质也可以有默认实现
trait Greeter {
def greet(name: String): Unit =
println("Hello, " + name + "!")
}
trait Greeter:
def greet(name: String): Unit =
println("Hello, " + name + "!")
你可以使用 extends
关键字扩展特质,并使用 override
关键字覆盖实现
class DefaultGreeter extends Greeter
class CustomizableGreeter(prefix: String, postfix: String) extends Greeter {
override def greet(name: String): Unit = {
println(prefix + name + postfix)
}
}
val greeter = new DefaultGreeter()
greeter.greet("Scala developer") // Hello, Scala developer!
val customGreeter = new CustomizableGreeter("How are you, ", "?")
customGreeter.greet("Scala developer") // How are you, Scala developer?
class DefaultGreeter extends Greeter
class CustomizableGreeter(prefix: String, postfix: String) extends Greeter:
override def greet(name: String): Unit =
println(prefix + name + postfix)
val greeter = DefaultGreeter()
greeter.greet("Scala developer") // Hello, Scala developer!
val customGreeter = CustomizableGreeter("How are you, ", "?")
customGreeter.greet("Scala developer") // How are you, Scala developer?
在此,DefaultGreeter
仅扩展一个特质,但它可以扩展多个特质。
我们将在 稍后 深入介绍特质。
程序入口点
main 方法是 Scala 程序的入口点。Java 虚拟机需要一个名为 main
的 main 方法,该方法接受一个参数:一个字符串数组。
在 Scala 2 中,你必须手动定义一个 main 方法。使用对象,你可以按如下方式定义 main 方法
object Main {
def main(args: Array[String]): Unit =
println("Hello, Scala developer!")
}
在 Scala 3 中,使用 @main
注解,可以按如下方式从方法自动生成 main 方法
@main def hello() = println("Hello, Scala developer!")
更多资源
- Scala 书籍 概述