Scala泛型及限定

1 Scala泛型


1.1 泛型函数

   ClassTag[T]保存了泛型擦除后的原始类型T,提供给被运行时的。

[java]  view plain  copy
  1.     /* 
  2.      *  泛型[],中括号F、S、T都表示运行时参数类型, 
  3.      * ClassTag[T]保存了泛型擦除后的原始类型T,提供给被运行时的。 
  4.      */  
  5.     class Triple[F: ClassTag, S, T](val first: F, val second: S, val third: T)  
  6.       
  7.     object HelloTypeParam {  
  8.       def main(args: Array[String]): Unit = {  
  9.       
  10.         // 运行执行代码:val triple: Triple[String, Int, Double]  
  11.         val triple = new Triple("Spark"33.1415)  
  12.           
  13.         // 运行执行代码:val bigData: Triple[String, String, Char]  
  14.         val bigData = new Triple[String, String, Char]("Spark""Hadoop"'R');  
  15.           
  16.         // getData函数传入泛型为T的运行时List类型参数,返回list.length / 2的整数。  
  17.         def getData[T](list:List[T]) = list(list.length / 2)  
  18.         // List索引从0开始,执行结果:Hadoop  
  19.         println(getData(List("Spark","Hadoop",'R')));  
  20.           
  21.         // 获得getData函数引用  
  22.         val f = getData[Int] _  
  23.         // 调用getData函数,执行结果:4  
  24.         println(f(List(1,2,3,4,5,6)));  
  25.           
  26.       }  
  27.     }  

1.2 类型变量界定

泛型参数类型限定,限定具体类的可以调用特定的方法。

[java]  view plain  copy
  1.     /* 
  2.      * <:泛型类型限定符,表示只限定Comparable子类 
  3.      * Comparable[T]:为T下界,T:为Comparable[T]上界 
  4.      */  
  5.     class Pair[T <: Comparable[T]](val first: T, val second: T) {  
  6.       // compareTo方法进行比较,如果大于0返回first  
  7.       def bigger = if (first.compareTo(second) > 0) first else second  
  8.     }  
  9.       
  10.       
  11.     // 声明带T泛型参数的类  
  12.     class Pair_Lower_Bound[T](val first: T, val second: T) {  
  13.         // 传入的参数泛型T 必须为 R的父类(超类),返回构造Pair_Lower_Bound对象   
  14.         // R:为T的上界,T:为R下界    
  15.         def replaceFirst[R>:T](newFirst:R) = new Pair_Lower_Bound[R](newFirst,second)  
  16.     }  
  17.       
  18.     object TypeVariablesBounds {  
  19.       def main(args: Array[String]): Unit = {  
  20.         // 函数调用  
  21.         var pair = new Pair("Spark""Hadoop")  
  22.         // 执行结果:Spark  
  23.         println(pair.bigger)  
  24.       }  
  25.     }  

1.3 泛型视图限定


泛型视图限定:表示把传入不是Comparable[T]类型的隐式转换Comparable[T]类型,Comparable[T]:T下界,T:Comparable[T]上界。

注意:想用泛型的视图限定,这里有一个隐藏的条件,就是隐式转换。

基本类型和String类型会自动进行隐式转换,而我们自定义的类型就需要我们自己来写隐式转换了。

例如下方



[java]  view plain  copy
  1.     /* 
  2.      * <%泛型视图限定符,表示把传入不是Comparable[T]类型的 隐式传换 为Comparable[T]类型 
  3.      * Comparable[T]:为T下界,T:为Comparable[T]上界 
  4.      */  
  5.     class PairNotPerfect[T <% Comparable[T]](val first: T, val second: T) {  
  6.       // compareTo方法进行比较,如果大于0返回first  
  7.       def bigger = if (first.compareTo(second) > 0) first else second  
  8.     }  
  9.       
  10.     /* 
  11.      * <%泛型视图限定符,表示把传入不是Ordered[T]类型的 隐式传换 为Ordered[T]类型 
  12.      * Ordered[T]:为T下界,T:为Ordered[T]上界 
  13.      * Ordered继承: extends Any with java.lang.Comparable[A] 
  14.      */  
  15.     class PairBetter[T <% Ordered[T]](val first: T, val second: T) {  
  16.       def bigger = if (first.compareTo(second) > 0) first else second  
  17.     }  
  18.       
  19.     object ViewVariablesBounds {  
  20.       def main(args: Array[String]): Unit = {  
  21.         // 函数调用  
  22.         var pair = new PairNotPerfect("Spark""Hadoop");  
  23.         // 执行结果:Spark  
  24.         println(pair.bigger)  
  25.           
  26.         // 函数调用,Int类型进行隐式转换,将Int -> RichInt,RichInt实现了Comparable接口  
  27.         var pairInt = new PairNotPerfect(3,5)  
  28.         // 执行结果:5  
  29.         println(pairInt.bigger);  
  30.           
  31.         // 函数调用,Int类型进行隐式转换,将String -> RichString,RichString实现了Comparable接口  
  32.         var pairBetterStr = new PairBetter("Java","Scala");  
  33.         println(pairBetterStr.bigger);  
  34.           
  35.         // 函数调用  
  36.         var pairBetterInt = new PairBetter(2012);  
  37.         // 执行结果:Spark  
  38.         println(pairBetterInt.bigger)  
  39.       }  
  40.     }  

1.4 上下文界定

上下文界定:上下文界定是隐式参数的语法。如:Ordering:可以进行隐式转化的T类型。

[java]  view plain  copy
  1. class PairOrdering[T: Ordering](val first: T, val second: T) {  
  2.   // compareTo方法进行比较,如果大于0返回first  
  3.   def bigger(implicit ordered: Ordering[T]) = if (ordered.compare(first, second) > 0) first else second  
  4. }  
  5.   
  6. object ContextBounds {  
  7.   def main(args: Array[String]): Unit = {  
  8.     // 函数调用  
  9.     var pair = new PairOrdering("Spark""Hadoop")  
  10.     // 执行结果:Spark  
  11.     println(pair.bigger)  
  12.   }  
  13. }  

1.5 Manifest关键字

Manifest关键字:数组在声明时必须要求指定具体的类型,在函数泛型是无法知道具体类型,通过Manifest关键字使得运行时可以根据这个Manifest参数做更多的事情。

[java]  view plain  copy
  1.   def main(args: Array[String]): Unit = {  
  2.     /* 
  3.      *  定义方法array 
  4.      *  Manifest:需要运行时存储T的实际类型,运行时是做为参数运行在方法的上下文中。 
  5.      *  数组在定义时必须知道具体的类型,所以在声明方法时,需要添加Manifest 
  6.      */  
  7.     def arrayMake[T: Manifest](first: T, second: T) = {  
  8.       val r = new Array[T](2);  
  9.       r(0) = first;  
  10.       r(1) = second;  
  11.       // 返回r  
  12.       r;  
  13.     }  
  14.    
  15.     /* 
  16.      *  执行结果: 
  17.      *  1 
  18.      *  2 
  19.      */  
  20.     arrayMake(1,2).foreach(println)  
  21.   }     

1.6 ClassTag关键字

ClassTag[T]保存了泛型擦除后的原始类型T,提供给被运行时的。

[java]  view plain  copy
  1.     def main(args: Array[String]): Unit = {   
  2.        
  3.         /* 
  4.          * ClassTag:在运行时指定,在编译时无法确定的 
  5.          */  
  6.         def mkArray[T:ClassTag](elems:T*) = Array[T](elems:_*)  
  7.           
  8.         /* 
  9.          *  执行结果: 
  10.          *  42 
  11.          *  13 
  12.          */  
  13.         mkArray(42,13).foreach(println)  
  14.           
  15.         /* 
  16.          * 执行结果: 
  17.          * Japan 
  18.          * Brazil 
  19.          * Germany 
  20.          */  
  21.         mkArray("Japan","Brazil","Germany").foreach(println)  
  22.     }  

1.7 ClassManifest关键字

在引入Manifest的时候,还引入了一个更弱一点的ClassManifest,所谓的弱是指类型信息不如Manifest那么完整。用TypeTag替代了Manifest,用ClassTag替代了ClassManifest,原因是在路径依赖类型中,Manifest存在问题。

[java]  view plain  copy
  1. class A[T]  
  2. val m = manifest[A[String]]  
  3. // 执行结果:com.scala.type_param.Manifest_ClassTag$A$1[java.lang.String]  
  4. println(m);  
  5. val cm = classManifest[A[String]]  
  6. // 执行结果:com.scala.type_param.Manifest_ClassTag$A$1[java.lang.String]  
  7. println(cm);  

1.8 多重界定符

[java]  view plain  copy
  1.     /* 
  2.       // 表示:A和B为T上界 
  3.       T <: A with B 
  4.        
  5.       // 表示:A和B为T下界 
  6.       T >: A with B 
  7.        
  8.       // 表示:同时拥有上界和下界,并且A为下界,B为上界,A为B的子类,顺序不能颠倒。 
  9.       T >: A <: B 
  10.        
  11.       // 表示:类型变量界定,即同时满足AT这种隐式值和BT这种隐式值 
  12.       T:A:B 
  13.        
  14.       // 表示:视图界定,即同时能够满足隐式转换的A和隐式转换的B 
  15.       T <% A <% B  
  16.     */  

1.9 Scala类型约束

[java]  view plain  copy
  1. def main(args: Array[String]): Unit = {  
  2.   // A =:=B // 表示A类型等同于B类型  
  3.   // A <:<B   // 表示A类型是B类型的子类  
  4.   def rocky[T](i: T)(implicit ev: T <:< java.io.Serializable) {  
  5.     // 执行结果:Life is short ,you need spark!!!  
  6.     println("Life is short ,you need spark!!!")  
  7.   }  
  8.   rocky("Spark")  
  9. }  



猜你喜欢

转载自blog.csdn.net/huangyinzhao/article/details/80330037