类型参数

泛型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

原文地址:https://www.cnblogs.com/playforever/p/8022739.html