scala类型参数

1、 泛型
本质是参数化类型,
(1) Array可以取泛型参数及类型变量做其元素的类型。
(2) 对基本类型的支持
(3) 声明地点可变性
(4) 对于上下界的支持,以及将多个上界作为复合类型模式的安排。

import scala.collection.immutable.Queue
class Triple[F,S,T](val first:F,val second:S,val third:T)
object HelloTypeParameterization{
def main(args:Array[String]){
val triple=new Triple(“spark”,3,3.1415)
val bigdata=new Triple[String,String,Char](“Spark”,”Hadoop”,”R”)
val getDate[T](list:List[T])=list(list.length/2)
println(getData(List(“Spark”,”Hadoop”,”R”)))
val f=getData[Int]_
println(f(List(1,2,3,4,5)))
val queue=Queue(1,2,3,4)

}
}

2、 界定
java范类中的上下界界定。
类型上界

class User(val userName: String,val age: Int) extends Comparable[User] {
  override def compareTo(o: User): Int = this.age - o.age
}


object OrderingDemo extends App {

  /**
    * 类型界定,上界
    *
    * @param u1
    * @param u2
    * @tparam T T必须是Comparable[T]的子类
    * @return
    */
  def compare[T <: Comparable[T]](u1: T, u2: T): Int = { 

    if (u1.compareTo(u2) == 0) 0 else if (u1.compareTo(u2) > 0) 1 else -1

  }


  val u1 = new User("u1", 18)
  val u2 = new User("u2", 19)

  //  compare(u1,u2) //class User(userName: String, age: Int)的话,编译不通过

  println(compare(u1,u2)) //class User(val userName: String,val age: Int) extends Comparable[User]


}

上界

trait Similar {
  def isSimilar(x: Any): Boolean
}
case class MyInt(x: Int) extends Similar {
  def isSimilar(m: Any): Boolean =
    m.isInstanceOf[MyInt] &&
    m.asInstanceOf[MyInt].x == x
}
object UpperBoundTest extends App {
  def findSimilar[T <: Similar](e: T, xs: List[T]): Boolean =
    if (xs.isEmpty) false
    else if (e.isSimilar(xs.head)) true
    else findSimilar[T](e, xs.tail)
  val list: List[MyInt] = List(MyInt(1), MyInt(2), MyInt(3))
  println(findSimilar[MyInt](MyInt(4), list))
  println(findSimilar[MyInt](MyInt(2), list))
} 

下界

case class ListNode[+T](h: T, t: ListNode[T]) {
  def head: T = h
  def tail: ListNode[T] = t
  def prepend[U >: T](elem: U): ListNode[U] =
    ListNode(elem, this)
}
object LowerBoundTest extends App {
  val empty: ListNode[Null] = ListNode(null, null)
  val strList: ListNode[String] = empty.prepend("hello")
                                       .prepend("world")
  val anyList: ListNode[Any] = strList.prepend(12345)
}

3、 类型约束
类型等同约束 T=:=U 测试T类型是否等同于U类型
子类型约束 T<:

object TypeContrains{
def main(args:Array[String]){
//A=:=B
//A<:<B
def rocky[T](i:T)(implicit ev:T<:<java.io.Serializable){
println(“Lief is short, you need Spark!”)

}
rocky(“Spark”)
}
}

4、 类型系统
ClassTag特质用于存储被擦除的T类型的类信息,运行时的类信息,
TypeTag特质包涵T所有的静态类型信息

class A[T]
object Manifest_ClassTag{
def main(args:Array[String]){
def arrayMake[T:Manifest](first:T,second:T)={
val r=new Array[T](2);
r(0)=first;
r(1)=second;
r
}
arrayMake(1,2).foreach(println)

def mkArray[T:ClassTag](elems:T*)=Array[T](elems:_*)
mkArray(42,31).foreach(println)
mkArray(“Hello”,”Spark”,”and you”).foreach(println)


def manif[T](x:List[T])(implicit m:Manifest[T])={
if(m<:<manif[String])
println(“List String”)
else 
println(“Other type”)

}


val m=manifest[A[String]]
println(m)
val cm=classManifest[A[String]]
println(m)
}
}

5、 型变Variance
scala型变注释是在定义类型抽象时指定,
先说说协变和逆变(实际上还有非变)。协变和逆变主要是用来解决参数化类型的泛化问题。由于参数化类型的参数(参数类型)是可变的,当两个参数化类型的参数是继承关系(可泛化),那被参数化的类型是否也可以泛化呢?Java中这种情况下是不可泛化的,然而Scala提供了三个选择,即协变、逆变和非变。下面说一下三种情况的含义,首先假设有参数化特征Queue,那它可以有如下三种定义。
1)trait Queue[T] {}
这是非变情况。这种情况下,当类型S是类型A的子类型,则Queue[S]不可认为是Queue[A]的子类型或父类型,这种情况是和Java一样的。

2)trait Queue[+T] {}
这是协变情况。这种情况下,当类型S是类型A的子类型,则Queue[S]也可以认为是Queue[A}的子类型,即Queue[S]可以泛化为Queue[A]。也就是被参数化类型的泛化方向与参数类型的方向是一致的,所以称为协变。

3)trait Queue[-T] {}
这是逆变情况。这种情况下,当类型S是类型A的子类型,则Queue[A]反过来可以认为是Queue[S}的子类型。也就是被参数化类型的泛化方向与参数类型的方向是相反的,所以称为逆变。

接着看一个例子。

trait Function[-Arg,+Return]{ 
def apply(arg:Arg):Return 
} //defined trait Function 
val foo = new Function[Any,String]{
 override def apply(arg:Any) :String = s"Hello ,I received a $arg"
 } //foo: Function[Any,String] = $anon$1@72dda13a 
val bar:Function[String,Any] = foo 
//bar: Function[String,Any] = $anon$1@72dda13a
 foo("test") //res0: String = Hello ,I received a test 
bar("test") //res1: Any = Hello ,I received a test 

1
首先我们看一下Function的定义,在参数Arg位置被定义成了逆变,这个意味着我们可以在需要某个类型的时候用他的父类型替换,也就是老子换儿子,在返回值类型被定义成了协变,这就是在需要某个类型的时候用他的子类型替换,白话就是儿子换老子
2
我们看一下foo的定义,他的参数类型是Any,返回值类型是String,所以他的apply方法接收一个Any类型的参数,返回一个String类型的结果,这就是为什么foo(“test”)返回的是String类型的res0
3
我们再看一下bar的定义,参数类型为String,返回值类型为Any,所以如果能调用bar,需要传入String,结果是Any,也就是bar(“test”)是Any的原因
4
那么为什么可以写那句val bar:Function[String,Any] = foo
这就和型变有关了,由于Function参数位置逆变,所以需要String的时候我们能用他的老子Any替换,foo类型的参数位置正好是Any,同理返回值类型协变,需要的是Any,我们传入String自然也没错,所以可以通过编译并产生结果

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值