scala代码风格指南--<声明>

来源:互联网 发布:死寂木偶比利淘宝 编辑:程序博客网 时间:2024/04/27 08:06

英文原文:http://docs.scala-lang.org/style/

译文如下:


一、类

Class / Object / Trait构造函数应该全部声明为一行,除非该行变为“太长”(大约100个字符)。在这种情况下,将每个构造函数参数放在自己的行上,缩进四个空格:

class Person(name: String, age: Int) {}
class Person( name: String, age: Int, birthdate: Date, astrologicalSign: String, shoeSize: Int, favoriteColor: java.awt.Color) { def firstMethod: Foo = ...}

如果一个类/对象/特征扩展任何东西,则应用相同的一般规则,将其放在一行上,除非它超过约100个字符,然后缩进四个空格,每个项目在其自己的行上,两个 空格用于扩展; 这提供了构造函数参数和扩展之间的视觉分隔:

class Person(    name: String,    age: Int,    birthdate: Date,    astrologicalSign: String,    shoeSize: Int,    favoriteColor: java.awt.Color)  extends Entity  with Logging  with Identifiable  with Serializable {}


(一)、排序类元素

所有类/对象/特征成员都应该被声明为换行符。这个规则的唯一例外是varval这些可能没有介入的换行符,但是只有当没有一个字段具有Scaladoc,并且所有字段都有简单(最多20个ish字符,一行)定义时:

class Foo {  val bar = 42  val baz = "Daniel"
def doSomething(): Unit = { ... }
def add(x: Int, y: Int): Int = x + y}

字段应位于范围中的方法之前唯一的例外是如果 val具有块定义(多于一个表达式)并执行可被视为“类似方法”的操作(例如,计算a的长度List)。在这种情况下,val按照逻辑成员排序将要求,非平凡可以在文件的稍后点被声明。这条规则适用于vallazy val如果var声明遍布整个类文件,变得很难跟踪变化的别名


(二)、方法

方法应按照以下格式声明:

def foo(bar: Baz): Bin = expr

具有默认参数值的方法应以类似的方式声明,等号两边的空格:

def foo(x: Int = 6, y: Int = 7): Int = x + y

您应该为所有公共成员指定返回类型。考虑编译器检查的文档。它还有助于在面对不断变化的类型推断时保持二进制兼容性(如果推断方法实现的更改可能传播到返回类型)。

本地方法或私有方法可以省略它们的返回类型:

private def foo(x: Int = 6, y: Int = 7) = x + y

1、程序语法

避免使用程序语法,因为它很容易引起混淆,很简单。

// don't do thisdef printBar(bar: Baz) {  println(bar)}
// write this insteaddef printBar(bar: Bar): Unit = { println(bar)}

2、修饰符

方法修饰符应按以下顺序给出(每个适用时):

  1. 注释,每个都在自己的线上
  2. 覆盖修饰符(override
  3. 访问修饰符(protectedprivate
  4. 最终修饰符(final
  5. def



@Transaction@throws(classOf[IOException])override protected final def foo() {  ...}

3、主体

当方法体包含小于30(或更多)个字符的单个表达式时,应在单行上给出以下方法:

def add(a: Int, b: Int): Int = a + b

当方法主体是一个长于 30(或更多)字符但仍小于70(或更多)字符的单个表达式时,应在以下行中给出缩进两个空格:

def sum(ls: List[String]): Int =  ls.map(_.toInt).foldLeft(0)(_ + _)

这两种情况的区别是有些人为的。一般来说,您应该根据具体情况选择更易读的风格。例如,您的方法声明可能很长,而表达体可能相当短。在这种情况下,将表达式放在下一行可能更可读,而不是使声明行太长。

当一种方法的身体不能简单地表达在一条线上或具有非功能性(某些可变状态,局部或其他方式)时,身体必须用大括号括起来:

def sum(ls: List[String]): Int = {  val ints = ls map (_.toInt)  ints.foldLeft(0)(_ + _)}

包含单个match表达式的方法应以以下方式声明:

// right!def sum(ls: List[Int]): Int = ls match {  case hd :: tail => hd + sum(tail)  case Nil => 0}

不是这样的:

// wrong!def sum(ls: List[Int]): Int = {  ls match {    case hd :: tail => hd + sum(tail)    case Nil => 0  }}

4、多个参数列表

一般来说,如果有很好的理由,你应该只使用多个参数列表。这些方法(或类似声明的函数)具有更详细的声明和调用语法,对于经验不足的Scala开发人员来说更难理解。

你应该这样做的主要原因有三个:

  1. 流畅的API

    多个参数列表允许您创建自己的“控制结构”:

    1. def unless(exp: Boolean)(code: => Unit): Unit = if (!exp) code
    2. unless(x < 5) {
    3. println("x was not less than five")
    4. }
  2. 隐含参数

    当使用隐式参数,并使用implicit关键字时,它适用于整个参数列表。因此,如果只希望某些参数是隐式的,则必须使用多个参数列表。

  3. 对于类型推断

    当仅使用某些参数列表调用方法时,在调用其余参数列表时,类型参考者可以允许更简单的语法。考虑折叠

    1. def foldLeft[B](z: B)(op: (A,B) => B): B
    2. List("").foldLeft(0)(_ + _.length)
    3. // If, instead:
    4. def foldLeft[B](z: B, op: (B, A) => B): B
    5. // above won't work, you must specify types
    6. List("").foldLeft(0, (b: Int, a: String) => a + b.length)
    7. List("").foldLeft[Int](0, _ + _.length)

对于复杂的DSL,或类型名称长,可能难以将整个签名放在一行上。在这些情况下,将参数列表的开放式对齐,每行一个列表(即,如果您不能将它们全部放在一行,每行一个):

  1. protected def forResource(resourceInfo: Any)
  2. (f: (JsonNode) => Any)
  3. (implicit urlCreator: URLCreator, configurer: OAuthConfiguration): Any = {
  4. ...
  5. }

5、高阶函数

当声明高阶函数时,Scala允许在函数参数作为最后一个参数被调用时,在调用位置为这些函数提供更好的语法。例如,这是foldlSML中功能:

fun foldl (f: ('b * 'a) -> 'b) (init: 'b) (ls: 'a list) = ...

在Scala中,首选风格是正确的:

def foldLeft[A, B](ls: List[A])(init: B)(f: (B, A) => B): B = ...

通过最后放置函数参数,我们启用了如下所示的调用语法:

foldLeft(List(1, 2, 3, 4))(0)(_ + _)

此调用中的函数值不包括在括号中; 它在语法上与函数本身(foldLeft截然不同这种风格的优点是其简洁和清洁。


(三)、字段

字段应遵循方法的声明规则,特别注意访问修饰符排序和注释约定。

Lazy vals应该lazy直接使用关键字val

  1. private lazy val foo = bar()

二、功能值

Scala提供了许多用于声明函数值的不同语法选项。例如,以下声明完全相同:

  1. val f1 = ((a: Int, b: Int) => a + b)
  2. val f2 = (a: Int, b: Int) => a + b
  3. val f3 = (_: Int) + (_: Int)
  4. val f4: (Int, Int) => Int = (_ + _)

在这些风格中,(1)和(4)将始终是首选。(2)在这个例子中看起来更短,但是每当功能值跨越多行(通常情况下)时,这种语法就变得非常笨重。同样,(3)简明扼要。未经训练的眼睛很难破译这甚至产生功能值的事实。

当专门使用样式(1)和(4)时,很容易区分使用函数值的源代码中的位置。两种样式都使用括号,因为它们在单行上看起来很干净。


(一)、间距

括号和它们包含的代码之间不应有空格。
花括号应与其间的代码分开一个空格,给视觉上忙碌的大括号“呼吸室”。


(二)多表达式函数

大多数函数值不如上面给出的例子那么微不足道。许多包含多个表达式。在这种情况下,跨多个行分割函数值通常更易读。当这种情况发生时,只应使用风格(1),用括号代替括号。当包含大量代码时,样式(4)变得非常难以遵循。声明本身应该松散地遵循方法的声明样式,其中大括号与分配或调用在同一行,而闭括号在紧跟在函数的最后一行之后是自己的行。参数应与开启括号相同,如“arrow”(=>):

val f1 = { (a: Int, b: Int) =>  val sum = a + b  sum}

如前所述,函数值应尽可能地利用类型推断。




原创粉丝点击