博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
scala学习手记22 - 参数化类型的可变性
阅读量:6312 次
发布时间:2019-06-22

本文共 2004 字,大约阅读时间需要 6 分钟。

java 的代码中多少有些不是很严谨的内容,比如下面的这段代码:

public class Trouble {    public static void main(String[] args) {        Integer[] arr1 = new Integer[2];        arr1[0] = new Integer(1);        Object[] arr2 = arr1;        arr2[1] = new Double(2.0);        for (Integer i : arr1) {            System.out.println(i);        }    }}

这段代码是可以通过编译的。但是在执行的时候会报错。

使用scala编写类似的代码(印象中类似的代码之前也提到过):

var arr1:Array[Int] = new Array[Int](3)var arr2:Array[Any] = arr1

这段程序在编译期就会报错:因为不能将显式声明为Int型的数组赋给Any类型的数组。看一下报错信息:

将子类对象赋值给超类称为协变;将超类对象赋值给子类称为逆变。默认情况下,scala对这两种“变”都不支持。

不过有时候真的很需要协变的支持——不然继承的实现价值会小很多。看一下下面的代码:

class Pet(val name: String) {  override def toString() = name}class Dog(override val name: String) extends Pet(name)class Cat(override val name: String) extends Pet(name)def playWithPets(pets: Array[Pet]) {println("play with " + pets.mkString(","))}

在上面的代码里定义了一个playWithPets方法,因为我们既想遛狗又想逗猫,有事没事还想和海豚一起游泳。如果不能支持协变,那怎么办,总不能写PlayWithDog、PlayWithCat、PlayWithDelphin、PlayWithXXX…无穷匮也了。

先勉强试试下面的代码:

val dogs = Array(new Dog("Rover"), new Dog("Comet"))playWithPets(dogs)

根据前面的经验,这段代码在编译期就会报错:

看吧,遛狗都不行,别说逗猫调戏海豚什么的了。

既然说到这里了,那么肯定会有解决的方法,修改下playWithPets方法:

def playWithPets[T <: Pet](pets: Array[T]){}

这里用特殊的语法定义了playWithPets()。T<:Pet表示T所代表的类派生自Pet。通过这样的语法,我们告诉scala,我们需要的参数是Pet类型的数组或者继承自Pet类型的类的数组,换句话说就是为参数类型指定了一个上界,就是。这样调整后再编译执行就没问题了:

还有另一个特殊的语法“P>:Dog”。很明显的,可以类推出来这是为参数类型指定了一个下界。举个例子:偷猫逗狗结束了,需要把猫狗关进笼子里,可是没有猫笼子了,狗笼还有富余,那怎么办,把猫关进狗笼子啊(宠物都是单间待遇)。示例代码如下:

def sendToDogCaf[T >: Dog](pet: Pet) {  println("send " + pet + "to Dog's cafe")}sendToDogCaf(new Cat("Lily"))sendToDogCaf(new Pet("Rabbit"))

执行结果如下图:

就是这样,上面演示了如何在方法定义里控制方法的参数。

不过,如果是GM的话,当然也可以用杂兵下副本——如果是容器类的作者,当然也可以控制参数类型的可变性。如下面这段代码:

class MyList[+T]//...var list1 = new MyList[int]var list2: MyList[Any] = nulllist2 = list1 // OK

这里,+T告诉Scala允许协变;换句话说,在类型检查期间,让Scala接收某个类型或者其基类型。这样,就可以将MyList[Int]赋给MyList[Any]。对于Array[Int]而言,这是不可以的。不过,对于List(Scala程序库中实现的函数式List)而言,这是可以的。

类似的,参数化类型用-T替换T,就可以让Scala支持类型逆变。

###########

转载于:https://www.cnblogs.com/amunote/p/5693782.html

你可能感兴趣的文章
我的友情链接
查看>>
用sqlplus远程连接oracle命令
查看>>
多年一直想完善的自由行政审批流程组件【2002年PHP,2008年.NET,2010年完善数据设计、代码实现】...
查看>>
自动生成四则运算题目
查看>>
【翻译】使用新的Sencha Cmd 4命令app watch
查看>>
【前台】【单页跳转】整个项目实现单页面跳转,抛弃iframe
查看>>
因为你是前端程序员!
查看>>
数据库设计中的14个技巧
查看>>
Android学习系列(5)--App布局初探之简单模型
查看>>
git回退到某个历史版本
查看>>
ecshop
查看>>
HTML5基础(二)
查看>>
在GCE上安装Apache、tomcat等
查看>>
在Mac 系统下进行文件的显示和隐藏
查看>>
ue4(c++) 按钮中的文字居中的问题
查看>>
技能点
查看>>
读书笔记《乌合之众》
查看>>
Hadoop日记Day1---Hadoop介绍
查看>>
iOS 学习资料汇总
查看>>
centos7 yum安装jdk
查看>>