scala 高级类型

目录

单例类型(链式调用)

1
2
3
4
5
6
7
8
9
10
11
12
13
class Stu {

def show: this.type = {
println("show..")
this
}

def play: this.type = {
println("this play")
this
}

}

结构类型

只要类中有定义 append 方法 都可以调用如下方法,有点类似 ruby,python,go 的 interface 中的鸭子类型。这个简化了我们在接口中抽象方法。
本质上 scala 内部是通过反射的方式实现,所以性能上会有更大的开销。在使用的时候需要根据自己的业务场景,那些无法通过 trait 来抽象的时候可以考虑通过如下方法去实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  def appendLines(target: {def append(str: String): Any}, lines: Seq[String]) = {
for (line <- lines) {
target.append(line)
target.append(",")
}
}

val stu = new Stu
appendLines(stu, List("a", "b", "c"))
println(stu.info)

class Stu {

val info = new StringBuilder

def append(str: String) = {
info.append(str)
}
}

蛋糕模式 (依赖注入)

在 Scala 中,你可以通过特质和自身类型达到一个简单的依赖注入的效果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
case class User(name: String)

trait Repository {
def save(user: User): Unit
}

trait ServiceCompoent {
this: Repository =>
val user: User
def saveUser: Unit = this.save(user)
}

class Component extends ServiceCompoent with Repository {
override val user = User("feel")

override def save(user: User): Unit = {
println("保存..." + user.name)
}
}

val component = new Component
component.saveUser

抽象类型

我们可以在类或者 trait 中定义抽象类型,让子类去指定具体的类型。当然我们也可以使用类型参数 FileReader[String] 这种方式去指定,如果我们的抽象类型比较多的时候,我们就可以避免一长串类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
trait Reader {
type In

def read(file: String): In
}

class FileReader extends Reader {
override type In = String

override def read(file: String): In = {
s"${file} is reading"
}
}

型变注解

在类方法中如果碰到协变和逆变的错误时,通常的解决方法是引入一个新的类型参数[O >: T], 在方法签名里用新引入的类型参数。def ++[O >: T](other: MyList[O]): MyList[O] } 如下 ++ 方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
trait MyList[+T] {
def ++[O >: T](other: MyList[O]): MyList[O]
}

class Empty[T] extends MyList[T] {
override def ++[O >: T](other: MyList[O]): MyList[O] = other
}

scala> val empty = new Empty[String]
empty: Empty[String] = Empty@4f7d0008

scala> val ints = new Empty[Int]
ints: Empty[Int] = Empty@335eadca

scala> val any = new Empty[Any]
any: Empty[Any] = Empty@5a1c0542

scala> empty.++(any)
res2: MyList[Any] = Empty@5a1c0542

scala> empty.++(ints)
res3: MyList[Any] = Empty@335eadca // String 和 Int 的找出超类是 Any