博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Scala类型系统(sudden thought)
阅读量:5133 次
发布时间:2019-06-13

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

  http://docs.scala-lang.org/tour/lower-type-bounds.html中有一段代码

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

  文中说这段代码不会通过编译,因为Function1是contravariant 在参数的位置上。看到这里是一个头很多个大的。 However, this program does not compile because the parameter elem in prepend is of type B, which we declared covariant. This doesn’t work because functions are contravariant in their parameter types and covariant in their result types.

  先假设一下如果能编译通过的话。

  假设有这样子的一段代码

trait Animalcase class Dog() extends Animalcase class Cat() extends Animaldef addDogToAnimal(animalNode : ListNode[Animal]) : Unit{    animalNode.prepend(Dog())}
如果generic的类型是Animal的话,ListNode就变成如下 case class ListNode[Animal](h: Animal, t: Node[Animal]) extends Node[Animal] {  def prepend(elem: Animal) = ListNode[Animal](elem, this)  def head: Animal = h  def tail = t}
如果generic的类型是Cat的话,ListNode就变成如下 case class ListNode[Cat](h:Cat, t: Node[Cat]) extends Node[Cat] {  def prepend(elem:Cat) = ListNode[Cat](elem, this)  def head: Cat= h  def tail = t}

 addDogToAnimal方法接受一个ListNode[Animal],因为ListNode[Cat] 是 ListNode[Animal]的子类(因为是Covaraiance的)

 所以我们可以addDogToAnimal(ListNode(Cat(), Nil())),但是ListNode[Cat]只能prepend是Cat类型的对象。所以一定会出问题。

 解决方法就是在所有需要消费者方法中 introducing a new type parameter U that has B as a lower type bound.

trait Node[+B] { def prepend[U >: B](elem: U) } case class ListNode[+B](h: B, t: Node[B]) extends Node[B] { def prepend[U >: B](elem: U) = ListNode[U](elem, this) def head: B = h def tail = t } case class Nil[+B]() extends Node[B] { def prepend[U >: B](elem: U) = ListNode[U](elem, this) } 现在再来看刚才的问题 如果generic的类型是Animal的话,ListNode就变成如下
case class ListNode[Animal](h: Animal, t: Node[Animal]) extends Node[Animal] {  def prepend[U >: Animal](elem: Animal) = ListNode[Animal](elem, this)  def head: Animal = h  def tail = t}
如果generic的类型是Cat的话,ListNode就变成如下 case class ListNode[Cat](h:Cat, t: Node[Cat]) extends Node[Cat] {  def prepend[U >: Cat](elem:Cat) = ListNode[Cat](elem, this)  def head: Cat= h  def tail = t}
ListNode[Cat] 还是 ListNode[Animal]的子类 addDogToAnimal(ListNode(Cat(), Nil()))的时候,ListNode[Cat]的prepend方法可以接受所有U >: Cat 的对象 所以prepend方法可以接受Animal的对象作为参数。Dog也是一种Animal,所以animalNode.prepend(Dog())是没有问题的 在这里以一个java开发者来说,会觉得很不合理。明明是cat类型的ListNode,怎么可以加入dog。但这也是scala和java的不同呀。唉
 

 

 

  

转载于:https://www.cnblogs.com/robsann/p/7674918.html

你可能感兴趣的文章
Android Bitmap 和 Canvas详解
查看>>
最大权闭合子图
查看>>
oracle 创建暂时表
查看>>
201421410014蒋佳奇
查看>>
导入导出数据库和导入导出数据库表
查看>>
linux下操作mysql
查看>>
【03月04日】A股滚动市盈率PE历史新低排名
查看>>
Xcode5和ObjC新特性
查看>>
jvm slot复用
查看>>
高并发系统数据库设计
查看>>
LibSVM for Python 使用
查看>>
入坑的开始~O(∩_∩)O~
查看>>
Centos 7.0 安装Mono 3.4 和 Jexus 5.6
查看>>
Windows 7 上安装Visual Studio 2015 失败解决方案
查看>>
iOS按钮长按
查看>>
Shell流程控制
查看>>
CSS属性值currentColor
查看>>
[Leetcode|SQL] Combine Two Tables
查看>>
《DSP using MATLAB》Problem 7.37
查看>>
ROS lesson 1
查看>>