Scala进阶之路-Scala中的泛型介绍
作者:尹正杰
版权声明:原创作品,谢绝转载!否则将追究法律责任。
通俗的讲,比如需要定义一个函数,函数的参数可以接受任意类型。我们不可能一一列举所有的参数类型重载函数。那么程序引入了一个称之为泛型的东西,这个类型可以代表任意的数据类型。说白了泛型就是对数据类型的约束,例如 List,在创建 List 时,可以传入整形、字符串、浮点数等等任意类型。那是因为 List 在类定义时引用了泛型。
一.Scala中的泛型
1 /* 2 @author :yinzhengjie 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Scala%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 4 EMAIL:y1053419035@qq.com 5 */ 6 package cn.org.yinzhengjie.genericParadigm 7 8 import cn.org.yinzhengjie.genericParadigm.ClothesEnum.ClothesEnum 9 10 /**11 * 泛型: 就是类型约束12 * 定义一个泛型类Message13 */14 abstract class Message[C](content: C)15 /**16 * 我们在继承发型类时,可以自定义传入的值,比如下面两个继承子类17 */18 class StrMessage(content: String) extends Message(content)19 20 class IntMessage[Int](content: Int) extends Message[Int](content)21 /**22 * 定义一个泛型类Clothes,主构造方法有3个。23 */24 class Clothes[A, B, C](val clothType: A, val color: B, val size: C)25 /**26 * 定义一个枚举类ClothesEnum,它需要继承Enumeration27 */28 object ClothesEnum extends Enumeration {29 type ClothesEnum = Value30 val 上衣, 内衣, 裤子 = Value31 }32 33 object ScalaGenericParadigm {34 def main(args: Array[String]): Unit = {35 val clth1 = new Clothes[ClothesEnum, String, Int](ClothesEnum.上衣, "black", 175)36 println(clth1.clothType)37 38 val clth2 = new Clothes[ClothesEnum, String, String](ClothesEnum.上衣, "black", "XL")39 println(clth2.size)40 41 val neiYi = new Clothes[ClothesEnum, String, String](ClothesEnum.内衣, "Pink", "X")42 println(neiYi.color)43 }44 }45 46 47 48 /*49 以上代码执行结果如下:50 上衣51 XL52 Pink53 */
二.Scala的类型约束
1>.上界下界的图解说明
2>.类型约束的上界(Upper bounds)
1 /* 2 @author :yinzhengjie 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Scala%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 4 EMAIL:y1053419035@qq.com 5 */ 6 package cn.org.yinzhengjie 7 8 /** 9 * <: #表示的是Scala泛型中的上界,相当于Java泛型中的""10 * T<: Comparable[T] #表示T实现Comparable接口,不会发生隐式转换,除非用户显示的指定11 */12 class ComparableGeneralObject[T<: Comparable[T]](a:T,b:T){13 /**14 * @return : 返回比较大的数值15 */16 def bigger = {17 if (a.compareTo(b) > 0){18 a19 }else{20 b21 }22 }23 }24 25 26 object ScalaUpperLowerBounds {27 def main(args: Array[String]): Unit = {28 29 val res1 = new ComparableGeneralObject(Integer.valueOf(10),Integer.valueOf(20))30 println(s"res1 ====> ${res1.bigger} ")31 /**32 * 注意,Predef.scala中有定义隐式方法,它可以把int转换成Integer,类似我们在java所说的自动拆箱和装箱。33 * 而Predef在scala包下,因此其默认是导入的!34 * 对了,还有一点就是上线界定不会隐式转换,因此我们在定义res2对象时,需要显示的指定其泛型,否则会编译不通过哟!35 */36 val res2 = new ComparableGeneralObject[Integer](50,100)37 println(s"res2 ====> ${res2.bigger} ")38 39 }40 }41 42 43 44 /*45 以上代码执行结果如下:46 res1 ====> 2047 res2 ====> 10048 */
1 /* 2 @author :yinzhengjie 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Scala%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 4 EMAIL:y1053419035@qq.com 5 */ 6 package cn.org.yinzhengjie 7 8 9 /**10 * <: #表示的是Scala泛型中的上界,相当于Java泛型中的""11 * T<: Comparable[T] #表示T实现Comparable接口,不会发生隐式转换,除非用户显示的指定12 */13 class ComparableGeneralObject[T<: Comparable[T]](a:T,b:T){14 /**15 * @return : 返回比较大的数值16 */17 def bigger = {18 if (a.compareTo(b) > 0){19 a20 }else{21 b22 }23 }24 }25 26 class TeacherOrdered(val name:String,val age:Int) extends Ordered[TeacherOrdered] {27 /**28 * 重写比较的方法,比较方法按照年龄来比较29 */30 override def compare(that: TeacherOrdered): Int = {31 this.age - that.age32 }33 /**34 * 重写toString方法35 */36 override def toString: String = {37 this.name + "\t" + this.age38 }39 }40 41 42 object TeacherDemo{43 def main(args: Array[String]): Unit = {44 /**45 * 丹尼斯·里奇,C语言之父,UNIX之父。曾担任朗讯科技公司贝尔实验室下属的计算机科学研究中心系统软件研究部的主任一46 * 职。1978年与布莱恩·科尔尼干(Brian W. Kernighan)一起出版了名著《C程序设计语言(The C Programming Language)》,47 * 现在此书已翻译成多种语言,成为C语言方面最权威的教材之一。2011年10月12日(北京时间为10月13日),丹尼斯·里奇去世,48 * 享年70岁。49 */50 val t1 = new TeacherOrdered("丹尼斯·里奇", 70)51 /**52 * 林纳斯·本纳第克特·托瓦兹(Linus Benedict Torvalds, 1969年~ ),著名的电脑程序员、黑客。53 * Linux内核的发明人及该计划的合作者。托瓦兹利用个人时间及器材创造出了这套当今全球最流行的操作系统54 * (作业系统)内核之一。现受聘于开放源代码开发实验室(OSDL:Open Source Development Labs, Inc),55 * 全力开发Linux内核。56 */57 val t2 = new TeacherOrdered("Linus Benedict Torvalds", 49)58 59 60 val res1 = new ComparableGeneralObject(t1,t2)61 println(res1.bigger)62 }63 }64 65 66 /*67 以上代码执行结果如下:68 丹尼斯·里奇 7069 */
3>.类型约束的下界(Lower bounds)
类型的约束下界貌似不太好使哟,不推荐使用!目前也没有找到相关可靠的资源!
三.Scala中的视图界定(view bounds)
"<%"的意思是“view bounds”(视界),它比<:适用的范围更广,除了所有的子类型,还允许隐式转换过去的类型。
1 /* 2 @author :yinzhengjie 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Scala%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 4 EMAIL:y1053419035@qq.com 5 */ 6 package cn.org.yinzhengjie 7 8 9 /**10 * <% 是视图界定(view bounds)的标记,他会发生隐式转换11 */12 class ComparableObject[T <% Comparable[T]](a:T,b:T){13 /**14 * @return : 返回比较大的数值15 */16 def bigger = {17 if (a.compareTo(b) > 0){18 a19 }else{20 b21 }22 }23 }24 25 class TeacherOrdered(val name:String,val age:Int) extends Ordered[TeacherOrdered] {26 /**27 * 重写比较的方法,比较方法按照年龄来比较28 */29 override def compare(that: TeacherOrdered): Int = {30 this.age - that.age31 }32 /**33 * 重写toString方法34 */35 override def toString: String = {36 this.name + "\t" + this.age37 }38 }39 40 41 object TeacherDemo{42 def main(args: Array[String]): Unit = {43 /**44 * 丹尼斯·里奇,C语言之父,UNIX之父。曾担任朗讯科技公司贝尔实验室下属的计算机科学研究中心系统软件研究部的主任一45 * 职。1978年与布莱恩·科尔尼干(Brian W. Kernighan)一起出版了名著《C程序设计语言(The C Programming Language)》,46 * 现在此书已翻译成多种语言,成为C语言方面最权威的教材之一。2011年10月12日(北京时间为10月13日),丹尼斯·里奇去世,47 * 享年70岁。48 */49 val t1 = new TeacherOrdered("丹尼斯·里奇", 70)50 /**51 * 林纳斯·本纳第克特·托瓦兹(Linus Benedict Torvalds, 1969年~ ),著名的电脑程序员、黑客。52 * Linux内核的发明人及该计划的合作者。托瓦兹利用个人时间及器材创造出了这套当今全球最流行的操作系统53 * (作业系统)内核之一。现受聘于开放源代码开发实验室(OSDL:Open Source Development Labs, Inc),54 * 全力开发Linux内核。55 */56 val t2 = new TeacherOrdered("Linus Benedict Torvalds", 49)57 58 59 val res1 = new ComparableGeneralObject(t1,t2)60 println(res1.bigger)61 }62 }63 64 65 /*66 以上代码执行结果如下:67 丹尼斯·里奇 7068 */
1 /* 2 @author :yinzhengjie 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Scala%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 4 EMAIL:y1053419035@qq.com 5 */ 6 package cn.org.yinzhengjie 7 8 /** 9 * <% #是视图界定(view bounds)的标记,他会发生隐式转换10 */11 class ComparableGeneralObject[T<% Ordered[T]](a:T,b:T){12 /**13 * @return : 返回比较大的数值14 */15 def bigger = {16 if (a > b){17 a18 }else{19 b20 }21 }22 }23 24 /**25 * 改类需要实现Ordered特质26 */27 class TeacherOrdered(val name:String,val age:Int) {28 /**29 * 重写toString方法30 */31 override def toString: String = {32 this.name + "\t" + this.age33 }34 }35 36 37 object TeacherDemo{38 /**39 * 隐式将Teacher转换成Ordered40 */41 implicit def TeacherToOrderedTeacher(t:TeacherOrdered) = new Ordered[TeacherOrdered]{42 override def compare(that: TeacherOrdered): Int = {43 t.age - that.age44 }45 }46 47 48 def main(args: Array[String]): Unit = {49 /**50 * 丹尼斯·里奇,C语言之父,UNIX之父。曾担任朗讯科技公司贝尔实验室下属的计算机科学研究中心系统软件研究部的主任一51 * 职。1978年与布莱恩·科尔尼干(Brian W. Kernighan)一起出版了名著《C程序设计语言(The C Programming Language)》,52 * 现在此书已翻译成多种语言,成为C语言方面最权威的教材之一。2011年10月12日(北京时间为10月13日),丹尼斯·里奇去世,53 * 享年70岁。54 */55 val t1 = new TeacherOrdered("丹尼斯·里奇", 70)56 /**57 * 林纳斯·本纳第克特·托瓦兹(Linus Benedict Torvalds, 1969年~ ),著名的电脑程序员、黑客。58 * Linux内核的发明人及该计划的合作者。托瓦兹利用个人时间及器材创造出了这套当今全球最流行的操作系统59 * (作业系统)内核之一。现受聘于开放源代码开发实验室(OSDL:Open Source Development Labs, Inc),60 * 全力开发Linux内核。61 */62 val t2 = new TeacherOrdered("Linus Benedict Torvalds", 49)63 64 65 /**66 * 注意,由于比较的方法是由视图界定实现,因此它会自动调用隐式实现,即调用上面的“implicit def TeacherToOrderedTeacher(t:TeacherOrdered)...”函数签名。67 */68 val res1 = new ComparableGeneralObject(t1,t2)69 println(res1.bigger)70 }71 }72 73 74 /*75 以上代码执行结果如下:76 丹尼斯·里奇 7077 */
四.cala中的上下文界定(context bounds)
与 view bounds 一样 context bounds(上下文界定)也是隐式参数的语法糖。为语法上的方便,引入了”上下文界定”这个概念。
1 /* 2 @author :yinzhengjie 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Scala%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 4 EMAIL:y1053419035@qq.com 5 */ 6 package cn.org.yinzhengjie 7 8 /** 9 * 上下文界定也会发生隐式转换,比如我们定义柯里化函数(Currying)传递Ordering比较器,10 * 相当于Java中的Compatrator比较器。11 */12 class ComparableGeneralObject[T:Ordering](a:T,b:T)(implicit comparator:Ordering[T]){13 /**14 * @return : 返回比较大的数值15 */16 def bigger:T = {17 if (comparator.compare(a,b) > 0){18 a19 }else{20 b21 }22 }23 }24 25 /**26 * 改类需要实现Ordered特质27 */28 class TeacherOrdering(val name:String,val age:Int) {29 /**30 * 重写toString方法31 */32 override def toString: String = {33 this.name + "\t" + this.age34 }35 }36 37 object TeacherDemo{38 /**39 * 隐式创建一个比较器Ordering40 */41 implicit val comparator= new Ordering[TeacherOrdering]{42 override def compare(x: TeacherOrdering, y: TeacherOrdering): Int = {43 x.age - y.age44 }45 }46 47 def main(args: Array[String]): Unit = {48 /**49 * 丹尼斯·里奇,C语言之父,UNIX之父。曾担任朗讯科技公司贝尔实验室下属的计算机科学研究中心系统软件研究部的主任一50 * 职。1978年与布莱恩·科尔尼干(Brian W. Kernighan)一起出版了名著《C程序设计语言(The C Programming Language)》,51 * 现在此书已翻译成多种语言,成为C语言方面最权威的教材之一。2011年10月12日(北京时间为10月13日),丹尼斯·里奇去世,52 * 享年70岁。53 */54 val t1 = new TeacherOrdering("丹尼斯·里奇", 70)55 /**56 * 林纳斯·本纳第克特·托瓦兹(Linus Benedict Torvalds, 1969年~ ),著名的电脑程序员、黑客。57 * Linux内核的发明人及该计划的合作者。托瓦兹利用个人时间及器材创造出了这套当今全球最流行的操作系统58 * (作业系统)内核之一。现受聘于开放源代码开发实验室(OSDL:Open Source Development Labs, Inc),59 * 全力开发Linux内核。60 */61 val t2 = new TeacherOrdering("Linus Benedict Torvalds", 49)62 63 /**64 * 注意,由于比较的方法是由视图界定实现,因此它会自动调用隐式实现,即调用上面的“implicit def TeacherToOrderedTeacher(t:TeacherOrdered)...”函数签名。65 */66 val res1 = new ComparableGeneralObject(t1,t2)67 println(res1.bigger)68 }69 }70 71 72 /*73 以上代码执行结果如下:74 丹尼斯·里奇 7075 */
1 /* 2 @author :yinzhengjie 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Scala%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 4 EMAIL:y1053419035@qq.com 5 */ 6 package cn.org.yinzhengjie 7 8 /** 9 * 上下文界定也会发生隐式转换,上下文界定是视图界定的语法糖10 */11 class ComparableGeneralObject[T:Ordering](a:T,b:T){12 /**13 * @return : 返回比较大的数值14 */15 def bigger:T = {16 def inner(implicit comparator:Ordering[T]) = comparator.compare(a,b)17 if (inner > 0){18 a19 }else{20 b21 }22 }23 }24 25 /**26 * 改类需要实现Ordered特质27 */28 class TeacherOrdering(val name:String,val age:Int) {29 /**30 * 重写toString方法31 */32 override def toString: String = {33 this.name + "\t" + this.age34 }35 }36 37 object TeacherDemo{38 /**39 * 隐式创建一个比较器Ordering40 */41 implicit val comparator= new Ordering[TeacherOrdering]{42 override def compare(x: TeacherOrdering, y: TeacherOrdering): Int = {43 x.age - y.age44 }45 }46 47 def main(args: Array[String]): Unit = {48 /**49 * 丹尼斯·里奇,C语言之父,UNIX之父。曾担任朗讯科技公司贝尔实验室下属的计算机科学研究中心系统软件研究部的主任一50 * 职。1978年与布莱恩·科尔尼干(Brian W. Kernighan)一起出版了名著《C程序设计语言(The C Programming Language)》,51 * 现在此书已翻译成多种语言,成为C语言方面最权威的教材之一。2011年10月12日(北京时间为10月13日),丹尼斯·里奇去世,52 * 享年70岁。53 */54 val t1 = new TeacherOrdering("丹尼斯·里奇", 70)55 /**56 * 林纳斯·本纳第克特·托瓦兹(Linus Benedict Torvalds, 1969年~ ),著名的电脑程序员、黑客。57 * Linux内核的发明人及该计划的合作者。托瓦兹利用个人时间及器材创造出了这套当今全球最流行的操作系统58 * (作业系统)内核之一。现受聘于开放源代码开发实验室(OSDL:Open Source Development Labs, Inc),59 * 全力开发Linux内核。60 */61 val t2 = new TeacherOrdering("Linus Benedict Torvalds", 49)62 63 /**64 * 注意,由于比较的方法是由视图界定实现,因此它会自动调用隐式实现,即调用上面的“implicit def TeacherToOrderedTeacher(t:TeacherOrdered)...”函数签名。65 */66 val res1 = new ComparableGeneralObject(t1,t2)67 println(res1.bigger)68 }69 }70 71 72 /*73 以上代码执行结果如下:74 丹尼斯·里奇 7075 */
1 /* 2 @author :yinzhengjie 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Scala%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 4 EMAIL:y1053419035@qq.com 5 */ 6 package cn.org.yinzhengjie 7 8 /** 9 * 上下文界定也会发生隐式转换,上下文界定是视图界定的语法糖10 */11 class ComparableGeneralObject[T:Ordering](a:T,b:T){12 /**13 * @return : 返回比较大的数值14 */15 def bigger:T = {16 val comparator = implicitly[Ordering[T]]17 if (comparator.compare(a,b) > 0 ){18 a19 }else{20 b21 }22 }23 }24 25 /**26 * 改类需要实现Ordered特质27 */28 class TeacherOrdering(val name:String,val age:Int) {29 /**30 * 重写toString方法31 */32 override def toString: String = {33 this.name + "\t" + this.age34 }35 }36 37 object TeacherDemo{38 /**39 * 隐式创建一个比较器Ordering40 */41 implicit val comparator= new Ordering[TeacherOrdering]{42 override def compare(x: TeacherOrdering, y: TeacherOrdering): Int = {43 x.age - y.age44 }45 }46 47 def main(args: Array[String]): Unit = {48 /**49 * 丹尼斯·里奇,C语言之父,UNIX之父。曾担任朗讯科技公司贝尔实验室下属的计算机科学研究中心系统软件研究部的主任一50 * 职。1978年与布莱恩·科尔尼干(Brian W. Kernighan)一起出版了名著《C程序设计语言(The C Programming Language)》,51 * 现在此书已翻译成多种语言,成为C语言方面最权威的教材之一。2011年10月12日(北京时间为10月13日),丹尼斯·里奇去世,52 * 享年70岁。53 */54 val t1 = new TeacherOrdering("丹尼斯·里奇", 70)55 /**56 * 林纳斯·本纳第克特·托瓦兹(Linus Benedict Torvalds, 1969年~ ),著名的电脑程序员、黑客。57 * Linux内核的发明人及该计划的合作者。托瓦兹利用个人时间及器材创造出了这套当今全球最流行的操作系统58 * (作业系统)内核之一。现受聘于开放源代码开发实验室(OSDL:Open Source Development Labs, Inc),59 * 全力开发Linux内核。60 */61 val t2 = new TeacherOrdering("Linus Benedict Torvalds", 49)62 63 /**64 * 注意,由于比较的方法是由视图界定实现,因此它会自动调用隐式实现,即调用上面的“implicit def TeacherToOrderedTeacher(t:TeacherOrdered)...”函数签名。65 */66 val res1 = new ComparableGeneralObject(t1,t2)67 println(res1.bigger)68 }69 }70 71 72 /*73 以上代码执行结果如下:74 丹尼斯·里奇 7075 */