在一个文件中包含多个类和对象在 Scala 中被认为是好的形式,只要这些类紧密相关。
虽然没有必要,但方法返回的类型——在特征、类或对象上声明的命名函数——应该被声明为非私有方法。在: 之后需要有空格,但在它之前不能。
// methods declared on a class, trait or object
def length: Int = ...
def multiply(other: Foo): Foo = ...
def hypotenuse(a: Double, b: Double): Double = {
// function inside a method, so effectively private
def square(x: Double) = x * x
math.sqrt(square(a) + square(b))
}
关键字和括号之间应该有空格,但方法名和后面的括号之间不能用点表示法。对于运算符表示法,似乎没有可接受的括号样式 - 或者何时使用该表示法,但在这种表示法中,非字母数字方法周围应有空格。
// keywords
if (foo) ...
// dot notation
foo.doSomething(bar)
// operator notation
foo doSomething bar
foo + bar
在特殊情况下,当使用+ 连接字符串时,推荐的样式是不要在其周围使用空格。例如:
// concatenate strings
println("Name: "+person.name+"\tAge: "+person.age)
可以是单行的声明应该是单行的,除非嵌套不明显。
// one-liners
lazy val foo = calculateFoo
def square(x: Int) = x * x
不需要参数且没有副作用的方法应该不带括号使用,Java 方法除外,它们应该带括号使用。带有副作用的无参数方法应该与括号一起使用。
// without side-effects
val x = foo.length
val y = bar.coefficient
// with side-effects
foo.reverse()
包含单个表达式的声明不应包含在花括号内,除非其他语法考虑使之成为不可能。可以接受将表达式括在括号中以启用多行表达式,但我很少看到这种用法。
// single-line expression
def sum(list: List[Int]): Int = if (!list.isEmpty) list reduceLeft (_ + _) else 0
// multi-line expression
val sum = (
getItems
reduceLeft (_ + _)
)
在理解方面,保持生成器和条件垂直对齐似乎是一种公认的风格。至于yield,我看到它既与for对齐,又缩进。
// for-comprehensions
val squares =
for (x <- numbers)
yield x * x
// Curly brackets-style identation
val cells = for {
x <- columns
y <- rows
if x != y
} yield Cell(x, y)
// Parameter-style identation
val cells = for (x <- columns;
y <- rows;
if x != y)
yield Cell(x, y)
垂直对齐类声明的参数也是公认的风格。
说到缩进,两个空格是公认的约定。
大括号应从声明的同一行开始,并与该行垂直对齐。
// another example
def factorial(n: Int): Int = {
def fact(n: Int, acc: Int): Int = n match {
case 0 => acc
case x => fact(x - 1, x * acc)
}
fact(n, 1)
}
对于过程——返回类型为Unit的函数——,预期的样式应该是省略方法的类型和等号:
// procedures
def complain {
println("Oh, no!")
}
有些人认为这种风格容易出错,但是,因为错过等号会将返回 Unit 以外的内容的函数更改为过程。
标识符以驼峰形式编写(例如:identifiersHaveHumps),就像在 Java 中一样。对于字段、方法参数、局部变量和函数的名称,以小写字母开头。对于类、特征和类型,以大写字母开头。
与 Java 约定不同的是常量名称。在 Scala 中,惯例是使用以大写字母开头的标准驼峰式大小写。例如Pi 而不是PI、XOffset 而不是X_OFFSET。任何单例通常都遵循此规则。对于大小写匹配,以这种方式表示常量和单例具有实际意义:
import scala.Math.Pi
val pi = Pi // this identifier will be shadowed by the identifier in the function below
def isPi(n: Double): Boolean = n match {
case Pi => println("I got a true Pi."); true
case pi => println("I got "+pi+" and bounded it to an identifier named pi."); false
}
包名以小写字母开头。当在 import 语句中区分什么是包和什么不是包时,这特别有用。在前面的示例中,Math 不是包(它是单例),因为它以大写字母开头。
不推荐使用下划线字符 --_ --,因为该字符在 Scala 中有许多特殊含义。这些标识符规则可以在 Odersky, Spoon & Venners 的 Programming in Scala 的第 141 和 142 页上找到。
目前,我不记得其他情况,但请随时要求澄清具体问题。其中一些规则是明确规定的,另一些则更多是社区共识。我试图忽略我自己的偏好,但我可能失败了。
更重要的是,也许实际上并没有太多统一的约定。原因之一可能是 Scala 吸引了来自许多不同背景的人,例如函数式语言专家、Java 程序员和 Web 2.0 爱好者。