Scala类型系统(sudden thought)

  http://docs.scala-lang.org/tour/lower-type-bounds.html中有一段代码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.java

  先假设一下若是能编译经过的话。this

  假设有这样子的一段代码spa

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的)scala

 因此咱们能够addDogToAnimal(ListNode(Cat(), Nil())),可是ListNode[Cat]只能prepend是Cat类型的对象。因此必定会出问题。code

 解决方法就是在全部须要消费者方法中 introducing a new type parameter U that has B as a lower type bound.htm

若是generic的类型是Animal的话,ListNode就变成以下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) }
如今再来看刚才的问题

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]的prepend方法能够接受全部U >: Cat 的对象
因此prepend方法能够接受Animal的对象做为参数。Dog也是一种Animal,因此
animalNode.prepend(Dog())是没有问题的在这里以一个java开发者来讲,会以为很不合理。明明是cat类型的ListNode,怎么能够加入dog。但这也是scala和java的不一样呀。唉ListNode[Cat] 仍是 ListNode[Animal]的子类
addDogToAnimal(ListNode(Cat(), Nil()))的时候
相关文章
相关标签/搜索