编码规范的目标可以归纳为三类:
- 代码发现:作用在于使工程师能够轻松地推理代码,看懂其他工程师的意图。
- 代码一致性:作用在于使整个项目的编码风格保持一致。
- 错误防止:指那些有助于在生产代码里避免 bug 的样式规则。
设计编码规范应该采取的方法:
- 从错误防止规范开始;
- 开发一套代码发现相关的规范,应与团队使用的开发环境匹配;
- 最后是代码一致性规范,应考虑到自动化工具支持的需要。
空悬操作符是指一行代码的最后一个非空字符是一个操作符,有助于编译器判断语句真正结束的位置。
名称重整(name mangling):是指编译器修改或修饰类名或方法名,以便把它编译到底层的平台上。Scala 里名称重整用在嵌套类或辅助方法上。
当 Scala 必须生成匿名函数或匿名类时,Scala 会生成一个名字,包括函数或类所处的类名、字符串 annofun
和一个数字, 用 $
符号连接起来。
编译器也会对默认参数应用名称重整措施。Scala 里默认参数也是被编码成方法的,方法名为 default
加上用来表示参数在函数里的出现顺序的序号。这出现在方法名字空间(namespace)里而不是类名字空间里。方法名$default$序号
参数位置语法是指定义参数的次序和调用时传递给参数的次序一致。可以对部分参数采用参数位置语法,对其余的采用命名参数语法。
Scala 为参数名使用静态类型或变量,但是它会动态修改默认值。名字是静态绑定的,值是动态绑定的
class Parent {
def foo(bar: Int = 1, baz: Int = 2): Int = {println("super, bar:" + bar + ", baz:" + baz); bar + baz}
}
class Child extends Parent {
override def foo(baz: Int = 3, bar: Int = 4): Int = {println("baz:" + baz + ", bar:" + bar); super.foo(baz, bar)}
}
val p = new Parent
println(p.foo()) // 3
val x = new Child
println(x.foo()) // 7
val y: Parent = new Child
println(y.foo()) // 7
println(x.foo(bar = 1)) // 4
println(y.foo(bar = 5, baz = 6)) // 11
// println(y.foo(5, bar = 6)) // error: parameter 'bar' is already specified at parameter position 1
Scala 里的命名参数是根据静态类型来决定参数的顺序。
总是标记覆盖(override)方法
override 关键字用于区分一个方法是否要覆盖还是重载一个方法。
纯抽象方法是指只有声明没有实现的方法。类首次定义时,Scala 不要求使用 override 关键字。
类线性化指调用某个类的父类方法时的调用顺序。
trait Animal {
def talk: String
}
trait Cat extends Animal {
override def talk: String = "Meow"
}
trait Dog extends Animal {
override def talk: String = "Wookf"
}
val kittydoggy = new Cat with Dog
println(kittydoggy.talk)
val kitdog = new Dog with Cat
println(kitdog.talk)
如果不实用 override 关键字,将编译错误:inherits conflicting members:
对期望的优化进行标注
尾递归是指方法在最后一个语句调用自身。编译器会把尾递归优化为运行时的循环,而不是递归调用。优化的主要作用是避免栈溢出错误而不是提高速度。
tableswitch 字节码是一种比多重分支语句更有效率的分支语句。
要想 Scala 应用 tableswitch 优化,必须满足以下条件:
- 匹配的值必须是个已知的整数;
- 每个匹配语句都必须”简单“,不能包含类型检查、if 语句或抽取器。表达式的值必须在编译期可获得。
- 应该有多于两个的 case 语句。
object TableSwitch {
def func(x: Int) = x match {
case 1 => "one"
case 2 => "two"
case z => z + "?"
}
}
JVM 用 instanceof 字节码进行类、特质和对象的类型检查。Scala 必须把基础的整数打包成整数对象的形式来进行类型检查,这是 Scala 在 JVM 上对任何基础数据类型做类型检查的基本机制。
要优化尾递归调用,Scala 编译器需要以下条件:
- 方法必须是 final 或私有的。不能多态。
- 方法必须注明返回类型。
- 方法必须在其某个分支的最后一句调用自身。
要求尾递归优化用 @tailrec
注解对方法进行标注。
Scala 用户应该确保:
- 同行左大括号;
- 使用悬空操作符或括号;
- 使用有意义的名字;
- 参数命名保持一致
- 总是标记覆盖的方法。
欢迎关注我的微信公众号: coderbee笔记,可以更及时回复你的讨论。