在 Scala 中全部值都有一种对应的类型java
value.type
,返回类型 value
/ null
场景1:链式API调用时的类型指定app
class Super { def m1(t: Int) = {println(t); this} def m2(t: Int) = {println(t); this} } // 正常打印 new Super().m1(1).m2(2) class Child extends Super { def c1(t: Int) = {println(t); this} } // 异常 value c1 is not a member of Super new Child().m1(1).c1(2)
因为 Scala 会将this
推断为当前类(即Super
),所以没法完成链式调用
class Super { // 指定返回类型为调用方的 this def m1(t: Int): this.type = {println(t); this} def m2(t: Int): this.type = {println(t); this} } class Child extends Super { def c1(t: Int) = {println(t); this} } // 成功打印 new Child().m1(1).c1(2)
场景2:方法中使用 object
实例做为参数this
object Foo class Child extends Super { def c1(obj: Foo.type) = { if (obj == Foo) println("foo") this } }
Note:不可定义为def c1(obj: Foo),由于 Foo 为单例对象,而不是类型
Outer#Inner
场景:内部类使用时避免类型约束scala
class Outer { private val inners = ArrayBuffer[Inner]() class Inner (val arg1: Int) { val l = ArrayBuffer[Inner]() } def add(a: Int) = { val t = new Inner(a) inners += t t } } val a = new Outer val b = new Outer val a1 = a.add(1) val b1 = b.add(1) a1.l += b1 // error: type mismatch;
只须要在定义内部类时指定类型投影便可解决
// 表示适用于任何 Outer 类的 Inner 类 val l = ArrayBuffer[Outer#Inner]()
若是将上述例子改用
List
来实现,并不会报错,计算结果也会自动进行类型投射
object
、val
、this/super/super[S]...
不能包含 var
类型翻译
var t = new Outer() //...其余操做 val i = new t.Inner // 因为 t 可能会变动,编译器没法肯定其含义
a.b.c.T 内部被翻译成类型投射 a.b.c.type#T
type SomeAliasName
class
或 object
内部好处: 在引用类型时能够更加简洁code
class Book { import scala.collection.mutable._ // 为该类型取一个别名 type Index = HashMap[String, Int] // 使用时不在须要重复的定义复杂的数据类型 val map: Index = new Index() } new Book().map // scala.collection.mutable.HashMap[String,Int]
为抽象方法、字段、类型的定义某种规范对象
def appendLines(target: { def append(str: String): Any }, lines: Iterable[String]) { for (l <- lines) { // 这次 Scala 使用反射调用该方法 target.append(l); target.append("\n") } }
该方法第一个参数 target
即结构类型,表示使用任何包含该 append
方法的实例做为参数传入。get
因为反射的代价较大,不到万不得已不建议使用,如,有通用行为(append
),却没法共享trait
T1 with T2 with T3 ...
当须要提供多个特质时使用,即用于约束类型编译器
val image = new ArrayBuffer[java.awt.Shape with java.io.Serializable] val rect = new Rectangle(5, 10, 20, 30) image += rect // 正确,Rectangle 可序列化 image += new Area(rect) // 错误 Area 不可序列化
组合类型中也可以使用结构类型数学
Shape with Serializable { def contains(p: Point): Boolean }
String Map Int
可代替 Map[String, Int]
可参考数学运算中的表达方式
type x[A, B] = (String, Int) // 便可使用 String x Int 来表示 (String, Int)
:
操做符,这个是右关联的,好比 List
的操做
中缀类型名称能够是任意操做符,除了
*
,避免与类型定义冲突