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 Animal
case class Dog() extends Animal
case class Cat() extends Animal
def 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的不同呀。唉


  

Scala类型系统(sudden thought)的更多相关文章

  1. scala类型系统:24) 理解 higher-kinded-type

    首先我们从最基本的泛型来看: 现在我们对上面泛型中的类型参数再进一步,也是个泛型会如何呢? 可以看到,java中不支持类型参数也是泛型类型的情况,而scala支持.这是一个很重要的区别,scala在类 ...

  2. scala类型系统 type关键字

    和c里的type有点像. scala里的类型,除了在定义class,trait,object时会产生类型,还可以通过type关键字来声明类型. type相当于声明一个类型别名: scala> t ...

  3. 【Scala类型系统】自身类型(self type)引用

    定义 特质能够要求混入它的类扩展自还有一个类型,可是当使用自身类型(self type)的声明来定义特质时(this: ClassName =>).这种特质仅仅能被混入给定类型的子类其中. 如果 ...

  4. Scala类型系统——高级类类型(higher-kinded types)

    高级类类型就是使用其他类型构造成为一个新的类型,因此也称为 类型构造器(type constructors).它的语法和高阶函数(higher-order functions)相似,高阶函数就是将其它 ...

  5. Effective Scala

    Effective Scala Marius Eriksen, Twitter Inc.marius@twitter.com (@marius)[translated by hongjiang(@ho ...

  6. Scala之类型参数和对象

    泛型 类型边界 视图界定 逆变和协变 上下文界定 源代码 1.泛型 泛型用于指定方法或类可以接受任意类型参数,参数在实际使用时才被确定,泛型可以有效地增强程序的适用性, 使用泛型可以使得类或方法具有更 ...

  7. Scala中的空

    Scala的有即Any,Scala的无是Null,null,Nil,Nothing,None,Unit.那么这几种空有什么区别呢? 一.Null&null 很多人一辈子都没有走出这个无.Nul ...

  8. Scala学习笔记--特质trait

    http://outofmemory.cn/scala/scala-trait-introduce-and-example 与Java相似之处 Scala类型系统的基础部分是与Java非常相像的.Sc ...

  9. 了解Scala反射

    本篇文章主要让大家理解什么是Scala的反射, 以及反射的分类, 反射的一些术语概念和一些简单的反射例子. 什么是反射 我们知道, Scala是基于JVM的语言, Scala编译器会将Scala代码编 ...

随机推荐

  1. NHibernate教程(21)——二级缓存(下)

    本节内容 引入 使用NHibernate二级缓存 启用缓存查询 管理NHibernate二级缓存 结语 引入 这篇我还继续上一篇的话题聊聊NHibernate二级缓存剩下的内容,比如你修改.删除数据时 ...

  2. 用GDI+画验证码

    1.新建一个窗体应用程序,在上面拖一个pictureBox对象,为其添加单击事件 2.创建GDI对象.产生随机数画入图片中.画线条.最后将图片到pictureBox中,代码如下: private vo ...

  3. dnsmasq一次成功的配置

    第一次用这个小软件,感觉还不错,因为没有像bind那样配置起来繁琐,并且我们也不需要去配置很多文件,内外网访问互不干涉. 我是在centos6.5下进行配置的: 先说说自己的理解: dnsmasq先去 ...

  4. 201521123082 《Java程序设计》第13周学习总结

    201521123082 <Java程序设计>第13周学习总结 标签(空格分隔): java 1. 本周学习总结 以你喜欢的方式(思维导图.OneNote或其他)归纳总结多网络相关内容. ...

  5. 结对实验---基于GUI的四则运算

    详细代码:https://git.coding.net/wangluo24/NO.2.git 结对伙伴:吕志哲(201421123021) &本人.许明涛 201421123024 一.题目要 ...

  6. 201521123061 《Java程序设计》第六周学习总结

    201521123061 <Java程序设计>第六周学习总结 ***代码阅读:Child压缩包内 1. 本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核 ...

  7. 201521123067 《Java程序设计》第5周学习总结

    201521123067 <Java程序设计>第5周学习总结 1. 本周学习总结 1.1 尝试使用思维导图总结有关多态与接口的知识点. 1.2 可选:使用常规方法总结其他上课内容. ●在本 ...

  8. JAVA课程设计个人博客 学生基本信息管理 201521123117 李心宇

    1. 团队课程设计博客链接 http://www.cnblogs.com/ll321/p/7067598.html 2.个人负责模块或任务说明 ①主要有三个界面的设计,包括:登录界面,功能选择界面还有 ...

  9. Spring-java-模板设计模式

    1,模板设计模式指的是将相应的模板方法提取出来在专门的位置定义,然后把相同调用过程操作,通过模板来实现对于模板设计模式而言,一般有两种实现方式 1)基于继承的实现 2)基于组合的实现 Spring的J ...

  10. 手機Web頁面信息

    手機瀏覽器的寬度為980px: 使用980px寫頁面時,若是遇到字體變大情況,是因為block或者inline-block沒有設置寬高.設置即顯示正常. 980px設計,禁止手機頁面縮放: <m ...