带有方法定义的类型参数背后的动机

时间:2016-02-11 07:21:24

标签: scala generics

我是scala的新手。我有一节课:

abstract class List[T] {

  def isEmpty: Boolean
  def head: T
  def tail: List[T]
  def nth[T](elem : T, index: Int) : Int =
      if (this.isEmpty) throw new IndexOutOfBoundsException("Element not found")
      else if (head.equals(elem)) return index
      else tail.nth(elem, index+1)
}

无论实现如何,方法nth都可以使用或不使用Type参数[T]进行编写,即在定义中没有Type参数[T]的方法声明将生成同样的结果:

def nth(elem : T, index: Int) : Int =
      if (this.isEmpty) throw new IndexOutOfBoundsException("Element not found")
      else if (head.equals(elem)) return index
      else tail.nth(elem, index+1)

根据我的理解,没有使用带有方法定义的类型参数。如果是这样,为什么这个功能被添加到语言中?有人能用一个有用的例子解释这个功能背后的动机吗?在这种情况下进行了什么样的编译时检查?

更新:链接列表的其余实现:

class NilList[T] extends List[T]{

  def isEmpty:Boolean = true
  def head : Nothing = throw new NoSuchElementException("Nil node")
  def tail : Nothing = throw new NoSuchElementException("Nil node")
}

class ConsList[T] (val head: T, val tail: List[T]) extends List[T]{
  def isEmpty: Boolean = false
}

3 个答案:

答案 0 :(得分:2)

请考虑以下事项。

abstract class X[A] {
  def m1[A](arg: A)   // warning: A defined in method shadows A defined in class 
  def m2[B](arg: B)   // B can be unrelated to A
  def m3[C <: A](arg: C) // C must be subtype of A
  def m4[D >: A](arg: D) // D must be supertype of A
}

如您所见,方法类型参数可用于多种用途。

答案 1 :(得分:1)

  

根据我的理解,没有使用类型参数   方法定义。

只有在阴影类级别类型参数时,才允许在方法上使用类型参数。隐藏类型参数通常是程序员错误的结果,编译器能够捕获并警告您实际上正在隐藏现有类型参数。

除此之外,还有很多用例需要泛型类型参数,而不是类。假设您对类型T有一个现有的,不变的约束,并且您希望类型V具有T作为其上限,但也可以对派生进行操作类。你会这样做:

class Foo[T] {
    def playWithDerived[V <: T](param: V) = Unit {
        // Do stuff.
    }
}

还有许多其他情况,这会有所帮助。

答案 2 :(得分:1)

l.nth("foo", 0)上的

List[Int]将使用以下List进行编译:

abstract class List[T] {
    def isEmpty: Boolean
    def head: T
    def tail: List[T]
    def nth[T](elem : T, index: Int) : Int =
        if (this.isEmpty) throw new IndexOutOfBoundsException("Element not found")
        else if (head.equals(elem)) return index
        else tail.nth(elem, index+1)
}

但如果我们定义List如下所示,它会产生编译时错误:

abstract class List[T] {
    def isEmpty: Boolean
    def head: T
    def tail: List[T]
    def nth(elem : T, index: Int) : Int =
        if (this.isEmpty) throw new IndexOutOfBoundsException("Element not found")
        else if (head.equals(elem)) return index
        else tail.nth(elem, index+1)
}

后者是编写此代码的正确方法,为什么要在nth上调用List[T],其元素类型与T完全不同?

我很好奇如何使用这个抽象类来实现终止列表。看起来不像是(重新)实现链表的更好方法之一。

还要考虑Tabstract class List[+T]的协方差。