英文原文:http://docs.scala-lang.org/style/
译文如下:
一般来说,Scala使用“驼峰命名法”命名。也就是说,每个单词都被大写,除了可能的第一个单词:
UpperCamelCase
lowerCamelCase
names(_
)中的下划线实际上并不被编译器所禁止,而是强烈地不鼓励,因为它们在Scala语法中具有特殊意义。(但请看下面的例外。)
类应以上面的驼峰命名法命名:
class MyFairLady
这就模仿了类的Java命名约定。
对象名称类似于类名(较高的骆驼命名)。
一个例外是模仿一个包或功能。这不常见 例:
object ast {
sealed trait Expr
case class Plus(e1: Expr, e2: Expr) extends Expr
...
}
object inc {
def apply(x: Int): Int = x + 1
}
Scala包应遵循Java包命名约定:
// wrong!
package coolness
// right! puts only coolness._ in scope
package com.novell.coolness
// right! puts both novell._ and coolness._ in scope
package com.novell
package coolness
// right, for package object com.novell.coolness
package com.novell
/**
* Provides classes related to coolness
*/
package object coolness {
}
偶尔有必要使用进口资格 _root_
。例如,如果另一个net
在范围内,那么访问net.liftweb
我们必须写如下:
import _root_.net.liftweb._
不要过度使用_root_
。一般来说,嵌套包解析是一件好事,对减少导入杂乱非常有帮助。使用_root_
不仅消除了他们的好处,而且引入了另外的混乱。
方法的文字(字母)名称应在较低的tuo'feng情况下:
def myFairMethod = ...
本节不是Scala中惯用方法命名的综合指南。更多信息可以在方法调用部分找到。
Scala并没有遵循预谋的Java约定set
/ get
(分别)以增变和访问方法。而是使用以下约定:
isEmpty
)上面添加“`is`” 。只有当没有提供相应的变焦器时,才应该这样。请注意,对布尔访问器附加“ ” 的 Lift约定_?
是非标准的,不在Lift框架之外使用。对于mutator,方法的名称应该是_=
附加了“ ” 的属性的名称。只要在封闭类型上定义具有该特定属性名称的相应访问器,此约定将启用镜像分配的调用位置变异语法。请注意,这不仅仅是一个惯例,而是语言的要求。
不幸的是,这些约定违反了Java惯例,根据它们所代表的属性来命名由访问器和变异器封装的私有域。例如:
public class Company {
private String name;
在Scala中,领域和方法没有区别。实际上,字段完全由编译器命名和控制。如果我们想在Scala中采用bean getters / setter的Java约定,这是一个相当简单的编码:
class Company {
private var _name: String = _
虽然匈牙利语表示法非常丑陋,但它确实具有消除_name
变量的优点,而不会使标识符混乱。下划线为前缀的位置,而不是后缀以避免误输入任何危险name _
的替代name_
。大量使用Scala的类型推断,这样的错误可能会导致一个非常混乱的错误。
请注意,Java getter / setter范例通常用于解决缺少对属性和绑定的一级支持。在Scala中,有一些库支持属性和绑定。该约定是使用一个不可变的引用来引用一个包含自己的getter和setter的属性类。例如:
class Company {
val string: Property[String] = Property("Initial Value")
与Ruby不同,Scala 对括号中是否声明方法 (仅适用于arity -0的方法 )具有重要意义。例如:
def foo1() = ...
这些在编译时是不同的方法。虽然foo1
可以使用或不带括号来调用,foo2
但不能使用 括号进行调用。
因此,实际上非常重要的是,在适当的情况下应遵循适当的准则来声明一个没有括号的方法,而不是。
充当任何类型的访问器(封装字段或逻辑属性)的方法应该声明为无括号,除非它们具有副作用。虽然Ruby和Lift使用a !
来表示这一点,但是括号的使用是首选(请注意,流体API和内部域特定语言倾向于为了语法而打破下面给出的准则,这种异常不应被视为违反这些规则不适用于这些规则。在DSL中,语法对于约定应该是至关重要的)。
此外,呼叫现场应遵循声明; 如果用圆括号声明,请用圆括号表示。虽然有诱惑保存一些字符,如果你遵循这一准则,你的代码会多 可读性和可维护性。
// doesn't change state, call as birthdate
def birthdate = firstName
避免!尽管Scala有助于API设计领域的程度,但不能轻易地对具有符号名称的方法进行定义,特别是当符号本身是非标准的(例如>>#>>
)时。作为一般规则,符号方法名称有两个有效的用例:
actor1 ! Msg
)a + b
或c :: d
)在前一种情况下,只要语法实际上是有益的,就可以使用符号方法名称而不受惩罚。然而,在标准API设计过程中,符号方法名称应该严格保留用于纯功能操作。因此,可以定义>>=
用于连接两个单体的方法,但是不能定义<<
用于写入输出流的方法。前者在数学上是明确定义的,并且是副作用的,而后者不是这些。
作为一般规则,符号方法名称应该被很好地理解和自我记录。经验法则如下:如果您需要解释方法的作用,那么它应该有一个真正的描述性名称而不是一个符号。有一些非常罕见的情况,可以发明新的符号方法名称。赔率是,您的API不是其中之一!
具有符号名称的方法的定义应该被认为是Scala中的一个高级功能,只能由那些最精通其陷阱的人使用。不用担心,过多使用符号方法名称可以轻松地将最简单的代码转换为符号汤。
恒定名称应在上骆驼壳。类似于Java的static final
成员,如果成员是final,不可变,它属于一个包对象或一个对象,它可以被认为是一个常量:
object Container {
val MyConstant = ...
}
值:Pi
in scala.math
package是另一个例子。
方法,值和变量名应该在较低的骆驼情况下:
val myValue = ...
def myMethod = ...
var myVariable
对于简单类型参数,应使用单个大写字母(来自英文字母表),从A
(这不同于Java惯例开始T
)开始。例如:
class List[A] {
def map[B](f: A => B): List[B] = ...
}
如果type参数具有更具体的含义,应使用描述性名称,遵循类命名约定(与全大写样式相反):
// Right
class Map[Key, Value] {
def get(key: Key): Value
def put(key: Key, value: Value): Unit
}
如果类型参数的范围足够小,可以使用助记符代替较长的描述性名称:
class Map[K, V] {
def get(key: K): V
def put(key: K, value: V): Unit
}
理论上较高的类型与常规类型参数没有区别(除了它们的 种类至少 *=>*
不是简单的*
)。命名约定大致相似,但为了清楚起见,优选使用描述性名称而不是单个字母;
class HigherOrderMap[Key[_], Value[_]] { ... }
单字母形式(有时候)可以用于整个代码库中使用的基本概念,例如F[_]
Functor和M[_]
Monad。
在这种情况下,基本概念应该是团队所熟知和理解的,或者具有以下三级证据:
def doSomething[M[_]: Monad](m: M[Int]) = ...
在这里,绑定类型: Monad
提供必要的证据来通知读者M[_]
Monad的类型。
注释,如@volatile
应在较低的骆驼情况下:
class cloneable extends StaticAnnotation
这个约定在整个Scala库中使用,尽管它与Java注释命名不一致。
注意:即使在注释上使用类型别名时,也应用此约定。例如,使用JDBC时:
type id = javax.persistence.Id @annotation.target.field
@id
var id: Int = 0
由于Scala源于功能语言,所以本地名称很简单:
def add(a: Int, b: Int) = a + b
这在Java语言中是不好的做法,但 在Scala中是很好的做法。这个惯例是有效的,因为正确编写的Scala方法很短,只跨越一个表达式,很少超出几行。使用很少的本地名称(包括参数),因此不需要设计长的描述性名称。这个约定大大提高了大多数Scala资源的简洁性。这反过来提高了可读性,因为大多数表达式适合一行,方法的参数具有描述性类型名称。
该约定仅适用于非常简单的方法(非常简单的类的局部字段)的参数; 公共界面中的一切都应该是描述性的。另请注意,参数的名称现在是类的公共API的一部分,因为用户可以在方法调用中使用命名参数。