本页面讨论 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.
trait
中的 val
或 var
会在子类和人工 Foo$class.$init$
中生成代码lazy val
会在子类中生成代码使用特征,还是不使用特征?。抽象类不如特征灵活,但特征会给二进制兼容性带来更多问题。抽象类还具有更好的 Java 互操作性。
如果没有必要保持类开放,请将其密封。
如果没有必要保持类开放,请将其完成。
使用纯特征的类型类模式可能比子类化更容易维护二进制兼容性。
case 类涉及代码生成,这使得随着时间的推移更难维护二进制兼容性。
默认参数值实际上是代码生成,这使得它们难以维护。
以下是一些关于 sbt 公共 API 的其他指南。
定义数据类型。
def apply
应该保留用于伴生对象中的工厂方法,该方法返回类型 T
。
Vector
、List
或 Array
),而不是 Seq
scala.Seq
是 scala.collection.Seq
,它不是不可变的。默认使用 Vector
。如果需要恒定前置,请使用 List
。如果需要 Java 互操作性,请使用 Array
。请注意,在实现中使用可变集合是完全可以的。
如果你坚持使用集合操作(如 contains
和 subsetOf
),那么 Set
就可以了。通常,toSeq
会显式或隐式地调用,或者从 map
中调用一些带有副作用的方法。这会给代码引入不确定性。
与上面一样。这会引入不确定性。
不要使用函数和元组,而是将它们转换为特征。这适用于互操作性成为问题的地方,例如实现增量编译。
sbt-houserules 附带 scalafmt 用于一致地格式化源代码。
声明显式的 Unit
返回值。
鼓励使用这种风格
final class FooID {}
object FooID {
implicit val fooIdPicklerUnpicker: PicklerUnpickler[FooID] = ???
}
避免在伴生对象和包对象中定义隐式转换器。
假设 IO 模块引入了名为 RichURI
的 URL
扩展,而 LibraryManagement 引入了名为 GroupID
(用于 ModuleID
语法)的 String
扩展。这些隐式转换应该在各自包中名为 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)
....
}