泛型

  1. [T <: UpperBound] 上界,定义个上限,不能超过
  2. [T >: LowerBound] 下界,定义下限,不能低于
  3. [T <% ViewBound] 视图界定,如果你想标记某一个泛型可以隐式的转换为另一个泛型,可以使用[T <% Comparable[T]],由于scalaInt类型没有实现Comparable接口,所以我们需要将Int类型隐式的转换为RichInt类型
  4. [T : ContextBound] 上下文界定
  5. [+T] 斜变,方法返回
  6. [-T] 逆变,方法参数

在java中,T同时是A和B的子类型,称为多界,形式如: <T extends A & B>
在scala中,对上界和下界不能有多个,但是可以使用混合类型,如: [T <: A with B]
在java中,不支持下界的多界形式.如: <T super A & B>这是不支持的
在scala中,对复合类型依然可以使用下界,如: [T >: A with B]

例子

[T <: UpperBound]

  1. package gen
  2. class Boy(val name: String, var faceValue: Int) extends Comparable[Boy]{
  3. override def compareTo(o: Boy): Int = {
  4. this.faceValue - o.faceValue
  5. }
  6. }
  1. package gen
  2. class MrRight[T <: Comparable[T]] {
  3. // 方法也可以加泛型
  4. //def choose[T <: Comparable[T]] (first: T, second: T): T = {
  5. def choose(first: T, second: T): T = {
  6. if (first.compareTo(second) > 0) first else second
  7. }
  8. }
  9. object MrRight {
  10. def main(args: Array[String]): Unit = {
  11. val mr = new MrRight[Boy]
  12. val b1 = new Boy("xiaowang", 99)
  13. val b2 = new Boy("xiaoxia", 77)
  14. mr.choose(b1, b2)
  15. }
  16. }

[T <% ViewBound]

  1. package gen
  2. class Girl(val name: String, var faceValue: Int) {
  3. }
  1. package gen
  2. object MyPreDef {
  3. //隐式转换
  4. implicit def girl2Ordered(g : Girl) = new Ordered[Girl] {
  5. //比较规则放这里
  6. override def compare(that: Girl): Int = {
  7. g.faceValue - that.faceValue
  8. }
  9. }
  10. }
  1. package gen
  2. //viewbound,必须有个隐式转换的方法
  3. class MissRight[T <% Ordered[T]] {
  4. def choose(first: T, second: T): T = {
  5. if (first > second) first else second
  6. }
  7. }
  8. object MissRight {
  9. def main(args: Array[String]): Unit = {
  10. //要在new之前导入,隐式转换,隐式转换里面写比较规则
  11. import MyPreDef.girl2Ordered
  12. val mr = new MissRight[Girl]
  13. val g1 = new Girl("ab", 90)
  14. val g2 = new Girl("mr", -1)
  15. val result = mr.choose(g1, g2)
  16. println(result.name)
  17. }
  18. }

[T : ContextBound]

Manifest上下文界定

Manifest是scala2.8引入的一个特质,用于编辑器在运行时也能获取泛型类型的信息.在jvm上,泛型参数类型T在运行时是被擦拭掉的,编译器把T当作Object来对待,所以T的具体信息是无法得到的.

为了使在运行时得到T的信息,scala需要额外通过Manifest来存储T的信息,并作为参数用在方法的运行时上下文

  1. def test[T](_x:T_ m:Manifest[T]) {...}

有了Manifest[T]这个记录T类型信息的参数m,在运行时就可以根据m来更准确的判断T了,但如果每个方法都这么写,让方法的调用者要额外传入m参数,非常不友好,而且该方法的设计对于scala而言简直就是一道伤疤.好在scala有隐式转换,隐式参数的功能,在这个地方可以用隐式参数来减轻调用者的麻烦

  1. object Main3 extends App {
  2. import scala.reflect.runtime.universe._
  3. def test2[A: TypeTag](_x: List[A]) = typeOf[A] match {
  4. case t if t =:= typeOf[String] => "String List"
  5. case t if t =:= typeOf[Int] => "Int List"
  6. }
  7. println(test2(List("s1", "s2")))
  8. println(test2(List(1, 2)))
  9. }

多界界定

可以同时拥有上界和下界

  1. T >: A <: B

这种情况下界必须写在前面,上界写在后面,位置不能反.同时,A要符合B的子类型,A与B不能是两个无关的类型

可以同时拥有多个view bounds

  1. T <% A <% B

这种情况要求必须同时存在T => A的隐式转换,和T => B的隐式转换

类型约束

类型约束,提供了限定类型的另一种方式,一共有3种声明
T =:= U意思为: T类型是否等于U类型
T <:< U意思为: T类型是否为U或U的子类型
T <%< U意思为: T类型是否被隐式(视图)转换为U

如果想使用上面的约束,需要添加”隐式类型证明参数”,比如:

  1. class Pair5[T](_val first: T_ val second: T)(implicit ev: T <:< Comparable[T]) { }