下限是如何工作的?

时间:2018-03-16 08:58:53

标签: scala

我已尽力了解下限工作在类型参数化方面的相关性,但无法理解它。

这里是一些下行示例代码。

class Queue[+T] (
  private val leading: List[T],
  private val trailing: List[T]
) {

  private def mirror = {
    if (leading.isEmpty){
      new Queue(trailing.reverse, Nil)
    }
    else
      this
  }

  def head = mirror.leading.head

  def tail = new Queue(mirror.leading.tail,
                       mirror.trailing)

  /* ====Wrong definition for enqueue====
   * def enqueue (item: T) =
   *   new Queue(leading, item :: trailing)
   */

  def enqueue[U >: T] (item: U) =
    new Queue[U](leading, item :: trailing)
}

class Fruit (val name: String) {
  override def toString = name
}
class Orange extends Fruit("orange")
class Apple  extends Fruit("apple")

val queueOrange: Queue[Orange] = new Queue[Orange](Nil, Nil)
queueOrange.enqueue(new Apple())
queueOrange.enqueue(new Orange())
queueOrange.enqueue(new Fruit("PineApple"))

val queueFruit: Queue[Fruit] = queueOrange
queueFruit.enqueue(new Orange())
queueFruit.enqueue(new Apple())
queueFruit.enqueue(new Fruit("Pineapple"))

here是执行上述代码的结果。

我有一些与上述代码和结果相关的问题。

  1. 我无法理解代码queueOrange.enqueue(new Apple())如何成功执行。据我所知,lowerbound限制了enqueue方法中的类型U应该是T的超类型,这是一个下限。然而,Apple和Orange都是同一个超类Fruit的兄弟姐妹。

  2. 我无法理解queueOrange.enqueue(新Apple())如何返回Queue [Fruit],即使我们将新的Orange()作为enqueue的参数提供。我认为这可能是因为Orange继承了Fruit,但是我无法理解整体机制是如何工作的,这会让问题1和问题2发生。

  3. 当我使用queueOrange和queueFruit在上面的代码中执行相同的操作时,我无法理解为什么结果会有所不同。

1 个答案:

答案 0 :(得分:1)

  

据我所知,下限限制了enqueue方法中的类型SERVER_DATE LOCAL_TIME LOCAL_TIME_4HRS_BACK -------------------- -------------------- -------------------- 3/16/2018 5:08:59 3/16/2018 14:38:59 3/16/2018 10:38:59 应该是U

的超类型

这不是完整的定义。 T或其任何祖先必须是U的超类型。如果我们将该表达式赋值给某个值,您会看到推断类型为T,因为编译器足够聪明,可以查看对象图。

如果您想确保Queue[Fruit]U的直接超类型,则需要稍微修改一下您的方法:

T

这样,编译器首先将def enqueue[U](u: U)(implicit ev: T <:< U) 绑定到U,然后搜索隐式证据,使Apple失效。

documentation for lower bounds shows this in a nutshell