1. 程式人生 > >Scala 基礎(1)—— 定義變數 & 定義函式

Scala 基礎(1)—— 定義變數 & 定義函式

1. 使用 val & var 定義變數

Scala 中的變數被分為2種:val 和 var。其含義於 Java 中的 final 關鍵字類似。

val 等同於被 final 修飾過的變數, 即一旦初始化便不可被重新賦值。

var 等同於未被 final 修飾過的變數,可以被重新賦值。

1   def main(args: Array[String]): Unit = {
2     val x = 1
3     x = 2 // 編譯錯誤
4   }

 

1   def main(args: Array[String]): Unit = {
2     var x = 1
3
x = 2 // 編譯成功 4 }

 

與 Java 相同,這裡的所謂不變性,是指引用不可變但是引用物件的狀態卻是可變的。

object Demo {

  def main(args: Array[String]): Unit = {
    val a = new A(1)
    a.x = 3
    println(a.x)
  }
}

class A(myX: Int) {
  var x: Int = myX
}

以上的例子,輸出結果為3。

 

 

2. 型別推斷

可以看出這裡有一個很明顯的與 Java 不同的地方:在宣告變數的時候,沒有顯式地給出型別

Scala 支援型別推斷,就是它能夠根據等式右側的值來推斷出這個引數的型別,例如上面的例子,x 的型別就是 scala.Int。

如果這並不是你所希望的 x 型別,例如,你期望初始化一個 Double 型別的,可以這麼定義:

val x: Double = 1

 

需要注意的是,如果只希望宣告變數,而不同時對變數進行初始化(一般來說這種情況只存在於定義成員變數),那麼就必須顯式定義型別,因為沒有等式右側去推測這個引數的實際型別。

abstract class MyClass {
  val y: Int
}

 

 

3. 強調引數可變性的意義

Scala 之所以使用 val 和 var 來定義引數,主要就是為了在宣告變數時,就確定它的可變性。

Scala 推薦能使用 val 的地方就是用 val,這麼做的優勢有:

  • Scala 是一門支援函數語言程式設計的語言,將變數定義成 val,可以有效地規避/減少函式的副作用。
  • 將成員變數定義成 val,可以保證構造的物件是不可變物件,這個性質在多執行緒程式設計中很有用。

關於不可變物件,可以參考《Java 併發程式設計實戰》P38(因為 Scala 是執行在 JVM 平臺上的,編譯之後本質其實就是 Java 的位元組碼檔案)

當滿足以下條件時,獨享才是不可變的:

  • 物件建立以後其狀態就不能改變。
  • 物件的所有域都是 final 型別的。
  • 物件是正確建立的(在物件建立期間,this 引用沒有溢位)。

 

 

4. 使用 def 定義函式

我們觀察以下函式的定義:

  def max(x: Int, y: Int): Int = {
    if (x > y) x else y
  }

 

定義一個函式包括以下部分:

  • def -> 定義函式的關鍵字
  • max -> 函式名
  • x: Int, y: Int -> 引數列表
  • Int -> 函式的結果型別
  • if (x > y) x else y -> 函式體

 

 

5. 函式的結果型別

由於 Scala 的型別推斷機制,函式的結果型別是可以省略的,也就是說沒這麼定義函式也是可行的:

  def max(x: Int, y: Int) = {
    if (x > y) x else y
  }

 

但是,有一種例外,就是遞迴地函式,必須給出結果型別:

  def factorial(x: Int) = {
    require(x >= 0)
    if (x > 1) x * factorial(x - 1) else 1 // 編譯錯誤
  }

雖然如此,但是一般推薦所有可以被外部訪問的函式(等價於 Java 中的 public),都顯式地加上結果型別。 

 

在上面 main 函式的例子中,結果型別 Unit 等價於 Java 中的 Void,表示函式並不會返回有實際意義的結果。