泛型Generic Type
Generic :一般的,普通的;通用的,不专用的;非专用装置的;非特有的
方法或者类可以接受任何类型的参数,参数类型只有在使用的时候或者调用的时候才被确定,类.特质.函数都可以有类型参数。
泛型可以使方法或者类更加通用。
泛型类:
scala> class fruit[A,B](var name:A,var price:B){println(s"I love $name,but $price dolar is too high!")}
defined class fruit
scala> val apple=new fruit[String,Int]("apple",5)
I love apple,but 5 dolar is too high!
apple: fruit[String,Int] = fruit@1e7113f8
scala> val apple=new fruit("apple",5)
I love apple,but 5 dolar is too high!
apple: fruit[String,Int] = fruit@7adf8932
scala> val banana=new fruit[String,String]("banana","five")
I love banana,but five dolar is too high!
banana: fruit[String,String] = fruit@6d4062fd
泛型函数:
scala> def method[T](arr:Array[T]){arr.foreach(println)}
method: [T](arr: Array[T])Unit
scala> method[Int](Array(1,2,3))
1
2
3
scala> method[String](Array("one","two","three"))
one
two
three
scala> method(Array('a','b',1))
97
98
1
scala> method(Array('a','b',"aaa"))
a
b
aaa
----------------------------
scala> 1.compareTo(100)
res8: Int = -1
scala> 1.compareTo(1)
res9: Int = 0
scala> 1.compareTo(-100)
res10: Int = 1
---------------------------------
类型变量界定
Java中, (? extends T), T称为上界, 比较容易理解, 代表T和T的子类, (? supers T), T称为下界
Scala中, 界却用于泛型类中的方法的参数类型上
对类型变量进行限制
scala> def compare[T1](a:T1,b:T1){if(a.compareTo(b)>=0)println(">=") else println("<")}
<console>:11: error: value compareTo is not a member of type parameter T1
def compare[T1](a:T1,b:T1){if(a.compareTo(b)>=0)println(">=") else println("<")}
^
这是错误的,我们并不知道a是否有compareTo方法。
要解决这个问题,我们可以添加一个上界 T <: Comparable[T] :
scala> def compare[T<:Comparable[T]](a:T,b:T){if(a.compareTo(b)>=0)println(">=") else println("<")}
compare: [T <: Comparable[T]](a: T, b: T)Unit
scala> compare[String]("100","50")
<
scala> compare[String]("tdd","mn")
>=
scala> compare[Int](100,50)
<console>:13: error: type arguments [Int] do not conform to method compare's type parameter bounds [T <: Comparable[T]]
compare[Int](100,50)
^
Int不是Comparable[Int]的子类,Scala Int类型没有实现Comparable接口
scala> compare[BigInt](100,50)
>=
scala> class compare[T<:Comparable[T]](a:T,b:T){def smaller()={ if(a.compareTo(b)<0) a else b;}}
defined class compare
scala> val comp=new compare[String]("gg","ss")
comp: compare[String] = compare@706243d4
scala> val comp=new compare[String]("gg","ss")
comp: compare[String] = compare@706243d4
scala> val comp=new compare[BigInt](100,50)
comp: compare[BigInt] = compare@2443ac97
scala> comp.smaller
res33: BigInt = 50
上界:
只允许T的超类U来替换T。 [U >: T]
下界:
只允许T的子类U来替代T。 [U <: T]
视图界定
部分类型不是Comparable[Int]的子类,导致报错,解决方法就是视图界定
<%关系意味着T可以被隐式的转换为Comparable[Int]
scala> class compare[T<%Comparable[T]](a:T,b:T){def smaller()={ if(a.compareTo(b)<0) a else b;}}
defined class compare
scala> val comp=new compare[String]("gg","ss")
comp: compare[String] = compare@1516d85a
scala> comp.smaller
res34: String = gg
scala> val comp=new compare[Int](100,50)
comp: compare[Int] = compare@889cd2f
scala> comp.smaller
res35: Int = 50
上下文界定
上下文界定形式 T:M,其中M是另一个泛型类,它要求必须有一个类型为M[T]的"隐形值"
scala> class pair[AA:Ordering](val f:AA,val s:AA){ def smaller(implicit ord:Ordering[AA])={ if (ord.compare(f,s)<0) f else s;}}
defined class pair
scala> val p1=new pair[BigInt](100,200)
p1: pair[BigInt] = pair@4cea9399
scala> p1.smaller
res164: BigInt = 100
scala> val p1=new pair[BigInt](100,20)
p1: pair[BigInt] = pair@4728b5f5
scala> p1.smaller
res165: BigInt = 20
scala> val p1=new pair(100,20)
p1: pair[Int] = pair@68694894
scala> p1.smaller
res166: Int = 20
scala> val p1=new pair("aa","bb")
p1: pair[String] = pair@be81a18
scala> p1.smaller
res167: String = aa
scala> val p1=new pair("aa",100)
<console>:18: error: No implicit Ordering defined for Any.
val p1=new pair("aa",100)
^
Manifest上下文界定
实例化一个Array[TT]对象,就需要一个Manifest[TT]对象
scala> def makarr[TT:Manifest](f:TT,s:TT)={ val arr=new Array[TT](2);arr(0)=f;arr(1)=s;arr}
makarr: [TT](f: TT, s: TT)(implicit evidence$1: Manifest[TT])Array[TT]
scala> makarr(100,20)
res171: Array[Int] = Array(100, 20)
scala> makarr("ddd",20)
res172: Array[Any] = Array(ddd, 20)
scala> makarr[String]("ddd","dd")
res176: Array[String] = Array(ddd, dd)
多重界定
类型变量可以同时有上界和下界,写法如下:
T<:Upper>:Lower
可以多个视图界定
T<%Compareable[T]<%String
可以多个上下文界定
T :Ordering:Manifest
类型约束
类型约束提供给你的是另一种限定类型的方式,总共有三种方式可供使用:
T=:=U //T是否等于U
T<:<U //T是否为U的子类型
T<%<U //T是否被视图(隐式)转换为U
这些约束并非内建在语言当中,他们是scala类库提供的特性。
scala> class pair[AA](val f:AA,val s:AA){ def smaller(implicit ord: AA<:<Ordered[AA])={ if (f.compareTo(s)<0) f else s;}}
defined class pair
scala> val p2=new pair("af","dd")
p2: pair[String] = pair@2b149f0a
scala> val p2=new pair[String]("af","dd")
p2: pair[String] = pair@4fc7a2d2
你可以构造出pair[File]对象,尽管File不是带先后次序的,只有调用smaller的时候才会报错
scala> p2.smaller
<console>:19: error: Cannot prove that String <:< Ordered[String].
p2.smaller
^
Option类的orNull方法,orNull的实现带有约束Null<:<A
scala> val fruits=Map((1,"apple"),(2,"orange"),(3,"banana"))
fruits: scala.collection.immutable.Map[Int,String] = Map(1 -> apple, 2 -> orange, 3 -> banana)
scala> fruits.get(2)
res219: Option[String] = Some(orange)
scala> fruits.getOrElse(2,0)
res220: Any = orange
scala> fruits.getOrElse(100,0)
res221: Any = 0
scala> fruits.get(50)
res222: Option[String] = None
scala> val f1=fruits.get(2)
f1: Option[String] = Some(orange)
//final def orNull[A1 >: String](implicit ev: Null <:< A1): A1
scala> f1.orNull
res225: String = orange
scala> val f1=fruits.get(5)
f1: Option[String] = None
scala> f1.orNull
res236: String = null
型变
函数如下
def makfrends(p:Pair[Person])
Student是Person的子类,但我们不能用Pair[Student]作为参数调用makfrends,因为Pair[Student] 和Pair[Person] 没有任何关系
如果想要有关系,Pair类的声明应该如下:
class Pair[+T](val f:T;val s:T)
+T 意味着该类型是T类型协变的,也就是说,它与T按同样的方向形变
Student是Person的子类型,Pair[Student] 也就是Pair[Person]的子类型了
另一个方向的型变 就是[-T],就是逆变了
swap [swɑp] 交换
定义一个不可变类Pair[T,S], 带一个swap方法,返回组件交换过位置的新对偶。
scala> class pair[T,S](first:T,second:S){def swap()={new pair[S,T](second,first)}}
defined class pair
scala> val p1=new pair("100",5)
p1: pair[String,Int] = pair@15fe6b60
scala> val p2=p1.swap()
p2: pair[Int,String] = pair@3a32539
scala> val p1=new pair(100,"dage")
p1: pair[Int,String] = pair@314ba847
scala> val p2=p1.swap()
p2: pair[String,Int] = pair@46007b16
定义一个可变类Pair[T],带一个swap方法,交换对偶中组件的位置。
scala> class pair[T](var f:T,var s:T){def swap(){ val tmp=f;f=s;s=tmp;println("f:"+f+";s:"+s)};}
defined class pair
scala> val p1=new pair(100,50)
p1: pair[Int] = pair@5120a555
scala> p1.swap
f:50;s:100
给定类Pair[T, S] ,编写一个泛型方法swap,接受对偶作为参数并返回组件交换过位置的新对偶。
scala> class pair[T,S](val first:T,val second:S){ def tostring{ println("f:"+first+";s:"+second)}}
defined class pair
scala> def swap[T,S](p:pair[T,S])={new pair(p.second,p.first)}
swap: [T, S](p: pair[T,S])pair[S,T]
scala> val mm=new pair("dd",84)
mm: pair[String,Int] = pair@785311b4
scala> swap(mm)
res58: pair[Int,String] = pair@7e282649
scala> swap(mm).first
res59: Int = 84
快学scala 17章例四
scala> class Pair[T](val first: T, val second: T) { def replaceFirst(newFirst: T) = new Pair[T](newFirst, second);override def toString = "(" + first + ", " + second + ")";
def replaceFirst2[R >: T](newFirst: R) = new Pair[R](newFirst, second);}
defined class Pair
scala> class Person(val name: String, val age: Int){override def toString = name + " " + age}
defined class Person
scala> class Student(val school: String, name: String, age: Int) extends Person(name, age){override def toString = super.toString + " " + school}
defined class Student
scala> val p1 = new Pair(new Person("tianyongtao", 98), new Person("xiaoma", 56))
p1: Pair[Person] = (tianyongtao 98, xiaoma 56)
scala> val p2 = p1.replaceFirst(new Student("beida", "liu", 101)) //newfirst:Student可以转化成Person(子->父)
p2: Pair[Person] = (liu 101 beida, xiaoma 56)
scala> val p3 = new Pair(new Student("skd", "gang", 81), new Student("shenda", "gggg", 25))
p3: Pair[Student] = (gang 81 skd, gggg 25 shenda)
scala> val p4 = p1.replaceFirst2(new Person("li", 77)) //replaceFirst2函数预定义了新的类型变量下界,second:student转化为Person(子->父)
p4: Pair[Person] = (li 77, xiaoma 56)
scala> val p4 = p3.replaceFirst2(new Person("li", 77))//replaceFirst2函数预定义了新的类型变量下界,second:student转化为Person(子->父)
p4: Pair[Person] = (li 77, gggg 25 shenda)
scala> val p4 = p3.replaceFirst(new Person("li", 77)) //newFirst:Person无法转化为Student(父->子)
<console>:13: error: type mismatch;
found : Person
required: Student
val p4 = p3.replaceFirst(new Person("li", 77))
^
经验证为发现RichInt,应该是BigInt,BigInt的存在丰富了Int,Int可以自动转换为BigInt
使用视图定界可以将Comparable[Int]转化为Comparable[BigInt]
scala> def middle[T](iter:Iterable[T]):T={ val ls=iter.toList;ls(ls.size/2) }
middle: [T](iter: Iterable[T])T
scala> middle("world")
res12: Char = r