Scala官方风格规范:https://docs.scala-lang.org/style/,根据具体使用情形做了精简,如下。
缩进
使用2个空格缩进,不用TAB。原因:Scala中嵌套结构非常多,缩进太多费空间。
// wrong!
class Foo {
def fourspaces = {
val x = 4
..
}
}
// right!
class Foo {
def twospaces = {
val x = 2
..
}
}
折行
当行字符太多时,折行。每个折行前2个空格。
val result = 1 + 2 + 3 + 4 + 5 + 6 +
7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 +
15 + 16 + 17 + 18 + 19 + 20
多参数的函数
参数多时,每个参数一行,依然遵守每个折行缩进2格,节省空间。
// right!
val myLongFieldNameWithNoRealPoint =
foo(
someVeryLongFieldName,
andAnotherVeryLongFieldName,
"this is a string",
3.1415)
// wrong!
val myLongFieldNameWithNoRealPoint = foo(someVeryLongFieldName,
andAnotherVeryLongFieldName,
"this is a string",
3.1415)
一般命名
类似java,scala使用“驼峰命名法”。
缩略词按正常单词对待,如:
Xhtml
maxId
下划线"_"由于在scala中有特殊的含义,命名中尽量不使用。
类/Traint/Object命名
// 类/Trait/Object 通常首字母大写:
class MyFairLady
方法命名
- 小写开头的驼峰:
def myFairMethod = ...
- 实现类似java的setter和getter方式:
class Company {
private var _name: String = _
def name = _name
def name_=(name: String) {
_name = name
}
}
- 不要重载符号操作符;
- 常量使用大写开头的驼峰,其他变量、值、方法用小写开头的驼峰
object Container {
val MyConstant = ...
val myValue = ...
def myMethod = ...
var myVariable
}
- 泛型
类型首字母大写即可,不要全大写:
// 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
}
- 短函数的简洁化书写
这种方式在scala中是被鼓励的,对简介性提升较高,对清晰性几乎没有牺牲。但仅限于很短的函数。
def add(a: Int, b: Int) = a + b
类型(Type)
- scala允许不显式声明变量类型。Q:什么情况下需要显式声明?A: 在存在调用方的情况下,尽量显式定义公用方法或变量的类型,确保不会改变返回值的类型从而造成错误。其他私有变量和函数可以立即看出类型或立即使用的情况不需要显式声明。
- 用下面方式声明类型,冒号后面接一个空格:
value: Type
- 函数类型的定义,:后、=>两边,=两边加空格,能省略括号就省略
def foo(f: Int => String) = ...
def bar(f: (Boolean, Double) => List[String]) = ...
- 结构体定义,类似多参数函数定义格式,不要挤在一行,除非非常的短
// wrong!
def foo(a: { def bar(a: Int, b: Int): String; val baz: List[String => String] }) = ...
// right!
private type FooParam = {
val baz: List[String => String]
def bar(a: Int, b: Int): String
}
def foo(a: FooParam) = ...
// ok
def foo(a: { val bar: String }) = ...
程序块(BLOCK)
def foo = {
...
}
类声明
初始化参数能放一行则放一行,太长了折行,参考多参数函数:
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 = …
}
当extend其他类时,类实现第一行空行,用于视觉分割
class Person(
name: String,
age: Int,
birthdate: Date,
astrologicalSign: String,
shoeSize: Int,
favoriteColor: java.awt.Color,
) extends Entity
with Logging
with Identifiable
with Serializable {
def firstMethod: Foo = …
}
类实现中,每种类型的定义之间用空行分割:
class Foo {
val bar = 42
val baz = "Daniel"
def doSomething(): Unit = { ... }
def add(x: Int, y: Int): Int = x + y
}
按如下顺序添加修饰字段
@Transaction
@throws(classOf[IOException])
override protected final def foo(): Unit = {
...
}
函数体
// 函数很短,用单行
def add(a: Int, b: Int): Int = a + b
// 稍长一些,但仍然是一句话,适当折行
def sum(ls: List[String]): Int =
ls.map(_.toInt).foldLeft(0)(_ + _)
def sum(ls: List[Int]): Int = ls match {
case hd :: tail => hd + sum(tail)
case Nil => 0
}
// 多行,用大括号包围
def sum(ls: List[String]): Int = {
val ints = ls map (_.toInt)
ints.foldLeft(0)(_ + _)
}
函数类型的值定义
scala 允许定义函数类型的值,使用如下几种定义方式以确保清晰:
val f1 = ((a: Int, b: Int) => a + b)
val f4: (Int, Int) => Int = (_ + _)
// 用多行实现函数是,用大括号整体包围
val f1 = { (a: Int, b: Int) =>
val sum = a + b
sum
}
控制结构
关键词后面加空格
// right!
if (foo) bar else baz
for (i <- 0 to 10) { ... }
while (true) { println("Hello, World!") }
// wrong!
if(foo) bar else baz
for(i <- 0 to 10) { ... }
while(true) { println("Hello, World!") }
if 结构中,如果有else则省略大括号,只有一个if不省略
val news = if (foo)
goodNews()
else
badNews()
if (foo) {
println("foo was true")
}
match case 中,case后的大括号全省略
news match {
case "good" => println("Good news!")
case "bad" => println("Bad news!")
}
函数调用
// 参数间空格,赋值等号两边空格
foo(42, bar)
target.foo(42, bar)
target.foo()
foo(x = 6, y = 7)
// 能用.就不用空格调用
names.toList
// 二元关系操作,两边加空格
"daniel" + " " + "spiewak" a + b
// 当使用高阶函数时,如map filter,如果是传入函数块,尽量用空格的方式
// wrong!
names.map { _.toUpperCase }.filter { _.length > 5 }
// right!
names map { _.toUpperCase } filter { _.length > 5 }