此頁面討論 sbt 1.0 的編碼風格和其他準則。
sbt 1.0 主要以 Scala 2.12 為目標。我們將針對 Scala 2.10 進行交叉建置。
在 1.0 發佈之前,我們應該清除棄用。
在 Scala 2.12 上,我們的目標應該是零警告。如果交叉建置需要,則可能會出現一個例外是棄用。
在充實特性/類別實作之前,通常從 Scaladoc 開始是很有用的,它可以強迫您考慮其存在的必要性。
所有新引入的公開特性和類別,以及在較小程度上的函式和方法,都應該有 Scaladoc。許多現有的 sbt 程式碼缺乏文件,我們需要隨著時間推移來修復這種情況。如果您發現有機會新增一些文件,或改善現有文件,那麼這也會有所幫助。
套件層級文件是描述各種元件如何互動的好地方,因此請考慮在可能的情況下新增/加強它。
如需更多關於良好 Scaladoc 風格的資訊,請參閱 Scaladoc 風格指南
我們可以向建置使用者公開的方法越少,sbt 就越容易維護。
針對介面進行編碼。
實作細節應該隱藏在 sbt.internal.x
套件後面,其中 x
可以是主套件的名稱 (例如 io
)。
具有較少相依函式庫的獨立模組更容易重複使用。
避免在 API 中公開外部類別,除了標準的 Scala 和 Java 類別之外。
如果模組對公眾沒有用處,則可以宣告為內部模組。
-encoding utf8
-deprecation
-feature
-unchecked
-Xlint
-language:higherKinds
-language:implicitConversions
-Xfuture
-Yinline-warnings
-Yno-adapted-args
-Ywarn-dead-code
-Ywarn-numeric-widen
-Ywarn-value-discard
-Xfatal-warnings
如果有無法避免的警告,則可以移除 -Xfatal-warnings
。
使用附加層名稱的套件名稱,例如 IO 層的 sbt.io
。發佈成品的組織名稱應保持為 org.scala-sbt
。
關於二進制彈性主題的良好概述是 Josh 在 2012 年的演講。此處的準則主要適用於公開的 API。
使用 MiMa。
def
宣告 trait
中的 val
或 var
會導致在子類別和人工 Foo$class.$init$
中產生程式碼lazy val
會導致在子類別中產生程式碼要特性,還是不要特性?。抽象類別不如特性靈活,但特性對二進制相容性構成更多問題。抽象類別也具有更好的 Java 互通性。
如果不需要保持類別開啟,請將其密封。
如果不需要保持類別開啟,請將其最終化。
具有純特性的類型類別模式可能比子類別更容易維護二進制相容性。
Case 類別涉及程式碼產生,這使得長期維護二進制相容性更加困難。
預設參數值實際上是程式碼產生,這使得它們難以維護。
以下是關於 sbt 公開 API 的其他準則。
定義資料類型。
def apply
def apply
應保留給傳回類型 T
的伴生物件中的工廠方法。
Vector
、List
或 Array
),而不是 Seq
scala.Seq
是 scala.collection.Seq
,它是不可變的。預設為 Vector
。如果需要常數前置,請使用 List
。如果需要 Java 互通性,請使用 Array
。請注意,在實作中完全可以使用可變集合。
Set
上呼叫 toSeq
或任何具有副作用的方法 如果您堅持使用集合操作 (例如 contains
和 subsetOf
),則 Set
很好。通常,會明確或隱含地呼叫 toSeq
,或者從 map
呼叫一些具有副作用的方法。這會將不確定性引入程式碼。
Map
上呼叫 toSeq
與上述相同。這會引入不確定性。
不要使用函式和元組,而是將它們轉換為 trait。這適用於需要考慮互操作性的情況,例如實作增量編譯。
sbt-houserules 內建 scalafmt,可一致地格式化原始碼。
明確宣告 Unit
返回值。
鼓勵使用這種風格
final class FooID {}
object FooID {
implicit val fooIdPicklerUnpicker: PicklerUnpickler[FooID] = ???
}
避免在伴生物件和 package 物件中定義隱式轉換器。
假設 IO 模組引入一個名為 RichURI
的 URL
擴充,而 LibraryManagement 引入一個名為 GroupID
的 String
擴充(用於 ModuleID
語法)。這些隱式轉換應該在各自套件中名為 syntax
的物件中定義
package sbt.io
object syntax {
implicit def uriToRichURI(uri: URI): RichURI = new RichURI(uri)
}
當所有層都可用時,sbt
套件也應該定義一個名為 syntax
的物件,它會轉發來自所有層的隱式轉換
package sbt
object syntax {
implicit def uriToRichURI(uri: URI): io.RichURI = io.syntax.uriToRichURI(uri)
....
}