千家信息网

好程序员大数据学习路线分享Scala系列之泛型

发表于:2025-01-23 作者:千家信息网编辑
千家信息网最后更新 2025年01月23日,好程序员大数据学习路线分享Scala系列之泛型,带有一个或多个类型参数的类是泛型的。泛型类的定义://带有类型参数A的类定义class Stack[A] {private var elements:
千家信息网最后更新 2025年01月23日好程序员大数据学习路线分享Scala系列之泛型

  好程序员大数据学习路线分享Scala系列之泛型,带有一个或多个类型参数的类是泛型的。

泛型类的定义:

//带有类型参数A的类定义
class Stack[A] {
private var elements: List[A] = Nil
//泛型方法
def push(x: A) { elements = x :: elements }
def peek: A = elements.head
def pop(): A = {
val currentTop = peek
elements = elements.tail
currentTop
}
}

泛型类的使用,用具体的类型代替类型参数A。

val stack = new Stack[Int]
stack.push(1)
stack.push(2)
println(stack.pop) // prints 2
println(stack.pop) // prints 1

1.协变
定义一个类型List[+A],如果A是协变的,意思是:对类型A和B,A是B的子类型,那么List[A]是List[B]的子类型。

abstract class Animal {
def name: String
}
case class Cat(name: String) extends Animal
case class Dog(name: String) extends Animal

Scala标准库有一个泛型类sealed abstract class List[+A],因为其中的类型参数是协变的,那么下面的程序调用时成功的。

object CovarianceTest extends App {
//定义参数类型List[Animal]
def printAnimalNames(animals: List[Animal]): Unit = {
animals.foreach { animal =>
println(animal.name)
}
}

val cats: List[Cat] = List(Cat("Whiskers"), Cat("Tom"))
val dogs: List[Dog] = List(Dog("Fido"), Dog("Rex"))
//传入参数类型为List[Cat]
printAnimalNames(cats)
// Whiskers
// Tom
//传入参数类型为List[Dog]
printAnimalNames(dogs)
// Fido
// Rex
}

2.逆变
定义一个类型Writer[-A],如果A是逆变的,意思是:对类型A和B,A是B的子类型,那么Writer[B]是Writer[A]的子类型。

abstract class Animal {
def name: String
}
case class Cat(name: String) extends Animal
case class Dog(name: String) extends Animal

定义对应上述类进行操作的打印信息类

abstract class Printer[-A] {
def print(value: A): Unit
}
class AnimalPrinter extends Printer[Animal] {
def print(animal: Animal): Unit =
println("The animal's name is: " + animal.name)
}

class CatPrinter extends Printer[Cat] {
def print(cat: Cat): Unit =
println("The cat's name is: " + cat.name)
}

逆变的测试

object ContravarianceTest extends App {
val myCat: Cat = Cat("Boots")

//定义参数类型为Printer[Cat]
def printMyCat(printer: Printer[Cat]): Unit = {
printer.print(myCat)
}

val catPrinter: Printer[Cat] = new CatPrinter
val animalPrinter: Printer[Animal] = new AnimalPrinter

printMyCat(catPrinter)
//可以传入参数类型为Printer[Animal]
printMyCat(animalPrinter)
}

3.上界
上界定义: T <: A ,表示类型变量T 必须是 类型A 子类

abstract class Animal {
def name: String
}

abstract class Pet extends Animal {}

class Cat extends Pet {
override def name: String = "Cat"
}

class Dog extends Pet {
override def name: String = "Dog"
}

class Lion extends Animal {
override def name: String = "Lion"
}
//参数类型须是Pet类型的子类
class PetContainer[P <: Pet](p: P) {
def pet: P = p
}
//Dog是Pet类型的子类
val dogContainer = new PetContainer[Dog](new Dog)
//Cat是Pet类型的子类
val catContainer = new PetContainer[Cat](new Cat)
//Lion不是Pet类型的子类,编译通不过
// val lionContainer = new PetContainer[Lion](new Lion)

4.下界
语法 B >: A 表示参数类型或抽象类型 B 须是类型A的父类。通常,A是类的类型参数,B是方法的类型参数。

上面这段代码,因为作为协变类型的B,出现在需要逆变类型的函数参数中,导致编译不通过。解决这个问题,就需要用到下界的概念。

trait Node[+B] {
def prepend[U >: B](elem: U): Node[U]
}

case class ListNode[+B](h: B, t: Node[B]) extends Node[B] {
def prepend[U >: B](elem: U): ListNode[U] = ListNode(elem, this)
def head: B = h
def tail: Node[B] = t
}

case class Nil[+B]() extends Node[B] {
def prepend[U >: B](elem: U): ListNode[U] = ListNode(elem, this)
}

测试

trait Bird
case class AfricanSwallow() extends Bird
case class EuropeanSwallow() extends Bird

val africanSwallowList= ListNode[AfricanSwallow](AfricanSwallow(), Nil())
val birdList: Node[Bird] = africanSwallowList
birdList.prepend(new EuropeanSwallow)

5 视界(view bounds)
注意:已过时,了解即可

视界定义: A <% B ,表示类型变量A 必须是 类型B`的子类,或者A能够隐式转换到B

class Pair_Int[T <% Comparable[T]] (val first: T, val second: T){
def bigger = if(first.compareTo(second) > 0) first else second
}

class Pair_Better[T <% Ordered[T]](val first: T, val second: T){
def smaller = if(first < second) first else second
}
object View_Bound {

def main(args: Array[String]) {
// 因为Pair[String] 是Comparable[T]的子类型, 所以String有compareTo方法
val pair = new Pair_Int("Spark", "Hadoop");
println(pair.bigger)

/**  * Scala语言里 Int类型没有实现Comparable;  * 那么该如何解决这个问题那;  * 在scala里 RichInt实现了Comparable, 如果我们把int转换为RichInt类型就可以这样实例化了.  * 在scala里 <% 就起这个作用, 需要修改Pair里的 <: 为<% 把T类型隐身转换为Comparable[Int]  * String可以被转换为RichString. 而RichString是Ordered[String] 的子类.  */val pair_int = new Pair_Int(3 ,45)println(pair_int.bigger)val pair_better = new Pair_Better(39 ,5)println(pair_better.smaller)

}

}

6 上下文界定(context bounds)
上下文界定的形式为 T : M, 其中M 必须为泛型类, 必须存在一个M[T]的隐式值.

class Pair_Context[T : Ordering](val first: T, val second: T){
def smaller(implicit ord: Ordering[T]) =
if(ord.compare(first, second) < 0) first else second
}

object Context_Bound {

def main(args: Array[String]) {

val pair = new Pair_Context("Spark", "Hadoop")println(pair.smaller)val int = new Pair_Context(3, 5)println(int.smaller)

}

}

类型 参数 子类 方法 程序 上下 上下文 上界 下界 变量 意思 视界 问题 测试 编译 数据 程序员 路线 学习 过时 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 戴尔服务器如何装win10 学校机房无网络服务器 大学网络安全工程师需要学什么 电信网络安全知识宣传进校园 海岛奇兵转移数据库 网络科技与网络技术 关于冬奥会期间网络安全保障情况工作报告 广东启付网络技术有限公司怎么样 计算机软件开发对一个企业 数据库技术协议 你画我猜为啥一直连接不上服务器 数据库主键选择 黄河鲲鹏服务器及pc机许昌 多台电脑连接打印服务器 龙仔网络技术 试论网络道德与网络安全3000 Vf数据库手机版 网络安全教育ppt命名 煜通网络技术有限公司 生化危机7都用了什么软件开发 数据库新技术相关资料 科技行业和互联网行业 延安公安网络安全保卫 内网数据库外网查询 陕西惠普服务器维修调试费用 邯郸学院网络技术专业 个人查询网络安全大队 武汉百鲤网络技术有限公司招聘 计算机网络技术专业课包含高数吗 亿清网络技术有限公司 电话
0