在此頁面中,我們將介紹 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 書籍 概觀