[scala代码风格指南]--命名规范

英文原文: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约定setget(分别)以增变和访问方法。而是使用以下约定:

  • 对于属性的访问者,方法的名称应该是属性的名称。
  • 在某些情况下,可以在布尔访问器(例如isEmpty)上面添加“`is`” 只有当没有提供相应的变焦器时,才应该这样。请注意,对布尔访问器附加“ ” 的 Lift约定_?是非标准的,不在Lift框架之外使用。
  • 对于mutator,方法的名称应该是_=附加了“ ” 的属性的名称只要在封闭类型上定义具有该特定属性名称的相应访问器,此约定将启用镜像分配的调用位置变异语法。请注意,这不仅仅是一个惯例,而是语言的要求。

     
       
  • class Foo {
  • def bar = ...
  • def bar_=(bar: Bar) {
  • ...
  • }
  • def isBaz = ...
  • }
  • val foo = new Foo
  • foo.bar // accessor
  • foo.bar = bar2 // mutator
  • foo.isBaz // boolean property

不幸的是,这些约定违反了Java惯例,根据它们所代表的属性来命名由访问器和变异器封装的私有域。例如:

public class Company {
    private String name;
public String getName () { return name ; }
public void setName ( String name ) { this . name = name ; } }

在Scala中,领域和方法没有区别。实际上,字段完全由编译器命名和控制。如果我们想在Scala中采用bean getters / setter的Java约定,这是一个相当简单的编码:

class Company {
  private var _name: String = _
def name = _name
def name_ =( name : String ) { _name = name } }

虽然匈牙利语表示法非常丑陋,但它确实具有消除_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() = ...
def foo2 = ...

这些在编译时是不同的方法。虽然foo1可以使用或不带括号来调用foo2 但不能使用 括号进行调用

因此,实际上非常重要的是,在适当的情况下应遵循适当的准则来声明一个没有括号的方法,而不是。

充当任何类型的访问器(封装字段或逻辑属性)的方法应该声明为括号,除非它们具有副作用。虽然Ruby和Lift使用a !来表示这一点,但是括号的使用是首选(请注意,流体API和内部域特定语言倾向于为了语法而打破下面给出的准则,这种异常不应被视为违反这些规则不适用于这些规则。在DSL中,语法对于约定应该是至关重要的)。

此外,呼叫现场应遵循声明; 如果用圆括号声明,请用圆括号表示。虽然有诱惑保存一些字符,如果你遵循这一准则,你的代码会 可读性和可维护性。

// doesn't change state, call as birthdate
def birthdate = firstName
// updates our internal state, call as age() def age () = { _age = updateAge ( birthdate ) _age }

符号方法名称

避免!尽管Scala有助于API设计领域的程度,但不能轻易地对具有符号名称的方法进行定义,特别是当符号本身是非标准的(例如>>#>>)时。作为一般规则,符号方法名称有两个有效的用例:

  • 域特定语言(例如actor1 ! Msg
  • 逻辑数学运算(例如a + bc :: d

在前一种情况下,只要语法实际上是有益的,就可以使用符号方法名称而不受惩罚。然而,在标准API设计过程中,符号方法名称应该严格保留用于纯功能操作。因此,可以定义>>=用于连接两个单体方法,但是不能定义<<用于写入输出流的方法。前者在数学上是明确定义的,并且是副作用的,而后者不是这些。

作为一般规则,符号方法名称应该被很好地理解和自我记录。经验法则如下:如果您需要解释方法的作用,那么它应该有一个真正的描述性名称而不是一个符号。有一些非常罕见的情况,可以发明新的符号方法名称。赔率是,您的API不是其中之一!

具有符号名称的方法的定义应该被认为是Scala中的一个高级功能,只能由那些最精通其陷阱的人使用。不用担心,过多使用符号方法名称可以轻松地将最简单的代码转换为符号汤。


五、常数,值,变量和方法

恒定名称应在上骆驼壳。类似于Java的static final 成员,如果成员是final,不可变,它属于一个包对象或一个对象,它可以被认为是一个常量:

object Container {
  val MyConstant = ...
}

值:Piin scala.mathpackage是另一个例子。

方法,值和变量名应该在较低的骆驼情况下:

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
}
// Wrong; don't use all-caps 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的一部分,因为用户可以在方法调用中使用命名参数。





  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值