Scala 【 13 类型参数 】

2023-03-09 14:40:20 浏览数 (2)

类型参数

​ Scala 的类型参数其实意思与 Java 的泛型是一样的,也是定义一种类型参数,比如在集合,在类,在函数中,定义类型参数,然后就可以保证使用到该类型参数的地方,就肯定,也只能是这种类型。从而实现程序更好的健壮性。

泛型类

​ 泛型类其实就是在类的声明中,定义一些泛型类型,然后在类内部,比如 field 或者 method,就可以使用这些泛型类型。

​ 使用泛型类,通常是需要对类中的某些成员,比如某些 field 和 method 中的参数或变量,进行统一的类型限制,这样可以保证程序更好的健壮性和稳定性。

​ 如果不使用泛型进行统一的类型限制,那么在后期程序运行过程中,难免会出现问题,比如传入了不希望的类型,导致程序出问题。

​ 在使用类的时候,比如创建类的对象,将类型参数替换为实际的类型,即可。

​ Scala 自动推断泛型类型特性:直接给使用了泛型类型的 field 赋值时, Scala 会自动进行类型推断。

代码语言:javascript复制
// 每个学生来自不同的地方,id可能是Int,可能是String

class Student[T](val localId:T){
    def getSchool(bornId:T) = "S-"   bornId   "-"   localId
}

val Li = new Student[Int](100)
泛型函数

​ 泛型函数,与泛型类类似,可以给某个函数在声明时指定泛型类型,然后在函数体内,多个变量或者返回值之间,就可以使用泛型类型进行声明,从而对某个特殊的变量,或者多个变量,进行强制性的类型限制。

​ 与泛型类一样,你可以通过给使用了泛型类型的变量传递值来让 Scala 自动推断泛型的实际类型,也可以在调用函数时,手动指定泛型类型。

代码语言:javascript复制
// 卡片售卖机,可以指定卡片的内容,内容可以是String类型或Int类型

def getCard[T](content:T) = {
    if(content.isInstanceOf[Int]) "card:001,"   content
    else if(content.isInstanceOf[String]) "card:002,"   content
    else "card: "   content
}

getCard[String]("hello card")
上边界Bounds

​ 在指定泛型类型的时候,有时,我们需要对泛型类型的范围进行界定,而不是可以是任意的类型。

​ 比如,我们可能要求某个泛型类型,它就必须是某个类的子类,这样在程序中就可以放心地调用泛型类型继承的父类的方法,程序才能正常的使用和运行。此时就可以使用上下边界 Bounds 的特性。

​ Scala的上下边界特性允许泛型类型必须是某个类的子类,或者必须是某个类的父类。

代码语言:javascript复制
class Person(val name:String){
    def sayHello = println("Hello, I'm "   name)
    def makeFriends(p:Person){
        sayHello
        p.sayHello
    }
}

class Student(name:String) extends Person(name)

class Party[T <: Person](p1:T, p2:T){
    def play = p1.makeFriends(p2)
}

// 测试
val p1 = new Student("Li")
val p2 = new Student("Chy")
val pa = new Party[Student](p1,p2)
pa.play
下边界 Bounds

​ 除了指定泛型类型的上边界,还可以指定下边界,即指定泛型类型必须是某个类的父类。

代码语言:javascript复制
class Father(val name:String)

class Child(name:String) extends Father(name)

def getIDCard[R >: Child](person:R){
    if(person.getClass == classOf[Child]) println("please tell us your parent's name")
    else if(person.getClass == classOf[Father]) println("sign your name for your child's ID card.")
    else println("Error.")
}

val father = new Father("Li")
val child = new Child("Lhy")

getIDCard[Father](father)
getIDCard[Child](child)
View Bounds

​ 上下边界 Bounds,虽然可以让一种泛型类型,支持有父子关系的多种类型。但是,在某个类与上下边界 Bounds 指定的父子类型范围内的类都没有任何关系,则默认是肯定不能接受的。

​ 然而,View Bounds 作为一种上下边界 Bounds 的加强版,支持可以对类型进行隐式转换,将指定的类型进行隐式转换后,再判断是否在边界指定的类型范围内。

代码语言:javascript复制
class Person(val name:String){
	def sayHello = println("Hello, I'm "   name)
    def makeFriends(p:Person){
        sayHello
        p.sayHello
    }
}

class Student(name:String) extends Person(name)

class Dog(val name:String) {
    def sayHello = println("Wank, I'm "   name)
}

// 隐式转换
implicit def dog2person(obj:Object):Person = if(obj.isInstanceOf[Dog]){
    val _dog = obj.asInstanceOf[Dog];
    new Person(_dog.name)} else Nil


class Party[T <% Person](p1:T,p2:T)

val stu = new Student("Li")
val dog = new Dog("WangCai")
val pa = new Party(stu,dog)
Context Bounds

​ Context Bounds 是一种特殊的Bounds,它会根据泛型类型的声明,比如“T: 类型”要求必须存在一个类型为“类型[T]”的隐式值。

代码语言:javascript复制
class Calculator[T: Ordering] (val number1: T, val number2: T) {
  def max(implicit order: Ordering[T]) = if(order.compare(number1, number2) > 0) number1 else number2
}
Manifest Context Bounds

​ 在 Scala 中,如果要实例化一个泛型数组,就必须使用 Manifest Context Bounds 。也就是说,如果数组元素类型为 T 的话,需要为类或者函数定义 [T: Manifest] 泛型类型,这样才能实例化 Array[T] 这种泛型数组。

代码语言:javascript复制
class Meat(val name:String)
class Vegetable(val name:String)

def packageFood[T:Manifest](food:T*) = {
    val foodPackage = new Array[T](food.length)
    for(i <- 0 until food.length) foodPackage(i) = food(i)
    foodPackage
}
Existential Type

​ 在 Scala 里,有一种特殊的类型参数,就是 Existential Type ,存在性类型。

0 人点赞