企业🤖AI Agent构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
[TOC] # 泛型 ~~~ [T <: UpperBound] 上界,定义个上限,不能超过 [T >: LowerBound] 下界,定义下限,不能低于 [T <% ViewBound] 视图界定,如果你想标记某一个泛型可以隐式的转换为另一个泛型,可以使用[T <% Comparable[T]],由于scala的Int类型没有实现Comparable接口,所以我们需要将Int类型隐式的转换为RichInt类型 [T : ContextBound] 上下文界定 [+T] 斜变,方法返回 [-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]` ~~~ package gen class Boy(val name: String, var faceValue: Int) extends Comparable[Boy]{ override def compareTo(o: Boy): Int = { this.faceValue - o.faceValue } } ~~~ ~~~ package gen class MrRight[T <: Comparable[T]] { // 方法也可以加泛型 //def choose[T <: Comparable[T]] (first: T, second: T): T = { def choose(first: T, second: T): T = { if (first.compareTo(second) > 0) first else second } } object MrRight { def main(args: Array[String]): Unit = { val mr = new MrRight[Boy] val b1 = new Boy("xiaowang", 99) val b2 = new Boy("xiaoxia", 77) mr.choose(b1, b2) } } ~~~ ## `[T <% ViewBound]` ~~~ package gen class Girl(val name: String, var faceValue: Int) { } ~~~ ~~~ package gen object MyPreDef { //隐式转换 implicit def girl2Ordered(g : Girl) = new Ordered[Girl] { //比较规则放这里 override def compare(that: Girl): Int = { g.faceValue - that.faceValue } } } ~~~ ~~~ package gen //viewbound,必须有个隐式转换的方法 class MissRight[T <% Ordered[T]] { def choose(first: T, second: T): T = { if (first > second) first else second } } object MissRight { def main(args: Array[String]): Unit = { //要在new之前导入,隐式转换,隐式转换里面写比较规则 import MyPreDef.girl2Ordered val mr = new MissRight[Girl] val g1 = new Girl("ab", 90) val g2 = new Girl("mr", -1) val result = mr.choose(g1, g2) println(result.name) } } ~~~ ## `[T : ContextBound]` ~~~ ~~~ # Manifest上下文界定 Manifest是scala2.8引入的一个特质,用于编辑器在运行时也能获取泛型类型的信息.在jvm上,泛型参数类型T在运行时是被擦拭掉的,编译器把T当作Object来对待,所以T的具体信息是无法得到的. 为了使在运行时得到T的信息,scala需要额外通过Manifest来存储T的信息,并作为参数用在方法的运行时上下文 ~~~ def test[T](x:T, m:Manifest[T]) {...} ~~~ 有了Manifest[T]这个记录T类型信息的参数m,在运行时就可以根据m来更准确的判断T了,但如果每个方法都这么写,让方法的调用者要额外传入m参数,非常不友好,而且该方法的设计对于scala而言简直就是一道伤疤.好在scala有隐式转换,隐式参数的功能,在这个地方可以用隐式参数来减轻调用者的麻烦 ~~~ object Main3 extends App { import scala.reflect.runtime.universe._ def test2[A: TypeTag](x: List[A]) = typeOf[A] match { case t if t =:= typeOf[String] => "String List" case t if t =:= typeOf[Int] => "Int List" } println(test2(List("s1", "s2"))) println(test2(List(1, 2))) } ~~~ # 多界界定 可以同时拥有上界和下界 ~~~ T >: A <: B ~~~ 这种情况下界必须写在前面,上界写在后面,位置不能反.同时,A要符合B的子类型,A与B不能是两个无关的类型 可以同时拥有多个view bounds ~~~ T <% A <% B ~~~ 这种情况要求必须同时存在`T => A`的隐式转换,和`T => B`的隐式转换 # 类型约束 类型约束,提供了限定类型的另一种方式,一共有3种声明 `T =:= U`意思为: T类型是否等于U类型 `T <:< U`意思为: T类型是否为U或U的子类型 `T <%< U`意思为: T类型是否被隐式(视图)转换为U 如果想使用上面的约束,需要添加"隐式类型证明参数",比如: ~~~ class Pair5[T](val first: T, val second: T)(implicit ev: T <:< Comparable[T]) { } ~~~