您的位置:首页 > 编程语言

[scala--代码风格指南]--声明

2017-07-26 13:51 337 查看
英文原文: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 {
}





(一)、排序类元素

所有类/对象/特征成员都应该被声明为换行符。这个规则的唯一例外是
var
val
。这些可能没有介入的换行符,但是只有当没有一个字段具有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
按照逻辑成员排序将要求,非平凡可以在文件的稍后点被声明。这条规则只适用于
val
lazy
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 this
def printBar(bar: Baz) {
println(bar)
}

// write this instead
def printBar(bar: Bar): Unit = {
println(bar)
}


2、修饰符

方法修饰符应按以下顺序给出(每个适用时):
注释,每个都在自己的线上
覆盖修饰符(
override

访问修饰符(
protected
private

最终修饰符(
final

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开发人员来说更难理解。

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

流畅的API

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

def unless(exp: Boolean)(code: => Unit): Unit = if (!exp) code

unless(x < 5) {

println("x was not less than five")

}


隐含参数

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

对于类型推断

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

def foldLeft[B](z: B)(op: (A,B) => B): B

List("").foldLeft(0)(_ + _.length)


// If, instead:

def foldLeft[B](z: B, op: (B, A) => B): B

// above won't work, you must specify types

List("").foldLeft(0, (b: Int, a: String) => a + b.length)

List("").foldLeft[Int](0, _ + _.length)


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

protected def forResource(resourceInfo: Any)

(f: (JsonNode) => Any)

(implicit urlCreator: URLCreator, configurer: OAuthConfiguration): Any = {

...

}



5、高阶函数

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

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


private lazy val foo = bar()



二、功能值

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

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


val f2 = (a: Int, b: Int) => a + b


val f3 = (_: Int) + (_: Int)


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
}


如前所述,函数值应尽可能地利用类型推断。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: