風格指南

類型

語言

推論

盡可能使用類型推論,但優先考慮清晰度,並在公開 API 中偏好明確性。

您幾乎不應該註解私人欄位或局部變數的類型,因為它們的類型通常會立即在其值中顯現

private val name = "Daniel"

但是,您可能仍希望在指定值具有複雜或不顯而易見的形式時顯示類型。

所有公開方法都應具有明確的類型註解。在這些情況下,類型推論可能會破壞封裝,因為它依賴於內部方法和類別的詳細資訊。如果沒有明確的類型,對方法或 val 的內部進行變更可能會在不發出警告的情況下變更類別的公開 API,並可能中斷用戶端程式碼。明確的類型註解也有助於改善編譯時間。

函數值

函數值支援類型推論的特例,值得單獨說明

val ls: List[String] = ...
ls.map(str => str.toInt)

在 Scala 已知道我們宣告的函數值的類型的情況下,不需要註解參數(在本例中為 str)。這是一種非常有用的推論,應盡可能優先使用。請注意,對函數值進行運算的隱式轉換會使此推論無效,並強制明確註解參數類型。

註解

類型註解應根據下列範本進行模式化

value: Type

這是大多數 Scala 標準函式庫和所有 Martin Odersky 範例採用的樣式。值和類型之間的空格有助於眼睛準確分析語法。將冒號放在值的結尾而不是類型的開頭的原因是為了避免在類似於此範例的情況中產生混淆

value :::

這實際上是有效的 Scala,宣告值為 :: 類型。顯然,前置式註解冒號會讓事情變得非常混亂。

歸屬

類型歸屬通常會與類型註解混淆,因為 Scala 中的語法相同。以下是歸屬的範例

  • Nil: List[String]
  • Set(values: _*)
  • "Daniel": AnyRef

歸屬基本上只是一個在編譯時為了類型檢查器而進行的上轉型。它的用途並不常見,但偶爾會發生。最常見的歸屬情況是使用單一 Seq 參數呼叫 varargs 方法。這是透過將 _* 類型歸屬於它來完成的(如上方的第二個範例)。

歸屬遵循類型註解慣例;冒號後有一個空格。

函式

函式類型應在參數類型、箭頭和傳回類型之間加上空格來宣告

def foo(f: Int => String) = ...

def bar(f: (Boolean, Double) => List[String]) = ...

應盡可能省略括號(例如,元數為 1 的方法,例如 Int => String)。

元數為 1

Scala 有特殊的語法來宣告元數為 1 的函式的類型。例如

def map[B](f: A => B) = ...

特別是,括號可以從參數類型中省略。因此,我們沒有宣告 f 的類型為 (A) => B,因為這會不必要地冗長。考慮更極端的範例

// wrong!
def foo(f: (Int) => (String) => (Boolean) => Double) = ...

// right!
def foo(f: Int => String => Boolean => Double) = ...

透過省略括號,我們節省了六個字元,並大幅提升了類型表達式的可讀性。

結構類型

如果結構類型長度小於 50 個字元,應在單一行中宣告。否則,應將它們拆成多行,並(通常)指定給它們自己的類型別名

// wrong!
def foo(a: { def bar(a: Int, b: Int): String; val baz: List[String => String] }) = ...

// right!
private type FooParam = {
  val baz: List[String => String]
  def bar(a: Int, b: Int): String
}

def foo(a: FooParam) = ...

較簡單的結構類型(小於 50 個字元)可以在內嵌中宣告和使用

def foo(a: { val bar: String }) = ...

在內嵌中宣告結構類型時,每個成員應以分號和單一空格分隔,開啟的大括弧後面應接著一個空格,而關閉的大括弧前面前面一個空格(如上方兩個範例所示)。

結構型態在執行階段以反射方式實作,而且本質上效能比名目型態差。開發人員應優先使用名目型態,除非結構型態提供明確的優點。

此頁面的貢獻者