简体   繁体   English

Scala类型不匹配基础类型和类与方法

[英]Scala Type Mismatch underlying type and class vs method

I'm implementing a class that acts as three stacks that rely on the same array (from Gayle Laakmann's cracking the coding interview). 我正在实现一个充当三个堆栈的类,它依赖于相同的数组(来自Gayle Laakmann的破解编码访谈)。

I'm having trouble understanding why this code results in type mismatches: 我无法理解为什么此代码会导致类型不匹配:

class ThreeStacks[A, B, C ](val stackSize:Int  = 1000) {

  /**
   * Push a value on to the first stack
   * @param value value of type A */
  def push1[A](value :A): Unit = stack1.push(value)

  /**
   * Push a value on to the second stack
   * @param value value of type B */
  def push2[B](value: B): Unit = stack2.push(value)

  /**
  * Push a value on to the third stack
  * @param value value of type C */
  def push3[C](value: C): Unit = stack3.push(value)

  /**
   * Pops the top value off the first stack
   * @return Some(value) at the top of the stack, None if the stack is empty */
  def pop1[A](): Option[A] = stack1.pop()

  /**
   * Pops the top value off the second stack
   * @return Some(value) at the top of the stack, None if the stack is empty */
  def pop2[B](): Option[B] = stack2.pop()

  /**
   * Pops the top value off the second stack
   * @return Some(value) at the top of the stack, None if the stack is empty */
  def pop3[C](): Option[C]  = stack3.pop()

  // the shared stacks
  private val stack1 = SharedStack[A]()
  private val stack2 = SharedStack[B]()
  private val stack3 = SharedStack[C]()

  // the shared stack class is simply a container for push and pop functions
  class SharedStack[T](val push: T => Unit, val pop: () => Option[T])

  // the sharedstack object is a factory setups a shared stack object with its proper push/pop functions that are received
  // from the stackmemory instance
  private object SharedStack{
    val stackMemory = new StackMemory(stackSize)

    def apply[T](): SharedStack[T] = {
      val stackTuple = stackMemory.registerStack[T]()
      new SharedStack(stackTuple._1, stackTuple._2)
    }
  }


  // the memory object responsible for handling the sharing of the array
  private class StackMemory(val stackSize: Int = 1000){

    // helps prevent the conflict warnings with immutable and mutable collections
    private val MutableMap = scala.collection.mutable.Map

    // the array that contains the stack nodes
    private val array = new Array[Option[StackNode[Any]]](stackSize)


    // keeps track of the heads of all the stacks
    private val registeredStackHeads = MutableMap[Int, Int]()

    // an index to help assign every new stack a unique key
    private var nextRegistrationIndex = 1

    // a list of indices in the array that have been freed
    private var freedIndices = List[Int]()

    // the next available free index, increments till it reaches the end of the array, different from the freeIndices list
    // in that it only is concerned with free cells while they are available at the end of the array
    private var nextFreeIndex = 0


    /**
     * Registers a stack within the memory object and returns the push/pop functions
     * @return the push/pop functions relevant for that stack */
    def registerStack[T](): (T  => Unit, () => Option[T]) = {
      val index = nextRegistrationIndex
      val noPreviousValueIndex = -1

      // register the index in the stack heads with an empty value
      registeredStackHeads(index) = noPreviousValueIndex

      nextRegistrationIndex += 1
      (push[T](index), pop[T](index) )
    }

    /**
     * Returns the push function for a stack at the given index
     * @param stackIndex the index of the requesting stack
     * @return  the push function for the stack */
    def push[T](stackIndex: Int) = {
      (value: T) =>  {

        // get the indices and initialize a stack node
        val headIndex = registeredStackHeads(stackIndex)
        val index = nextAvailableIndex()
        val stackNode = new StackNode[T](headIndex, value)

        // store the new stack head and place it in to the array
        registeredStackHeads(stackIndex) = index
        array(index) = Some(stackNode)
      }
    }

    /**
     * The pop function for the stack at a given index
     * @param stackIndex  the index of the requesting stack
     * @return the pop function for the stack */
    def pop[T](stackIndex: Int): () => Option[T] = {
      () => {
        val headIndex = registeredStackHeads(stackIndex)

        if(headIndex < 0) None else {
          array(headIndex) match {
            case Some(s : StackNode[T]) => {
              registeredStackHeads(stackIndex) = s.previousIndex
              freeIndex(headIndex)
              Some(s.value)
            }
            case _ => None
          }
        }
      }
    }

    // retrieve the next available index, throws an exception if there are no available indices
    private def nextAvailableIndex():Int = {

      // return a new index if the array isn't full otherwise throw an exception
      def newIndex() : Int = {
        if(nextFreeIndex >= stackSize){
          throw new Exception("No more room in stack array available")
        }
        else{
          val index = nextFreeIndex
          nextFreeIndex += 1
          index
        }
      }

      // first check if any of the old indices have been freed
      freedIndices match {
        case Nil => newIndex()
        case head::tail => freedIndices = tail; head
      }
    }

    // frees an index and adds it to the free indices list
    private def freeIndex(i: Int): Unit = {
      if (i >= array.length) throw new ArrayIndexOutOfBoundsException("The index to be freed does not exist in the array")
      array(i) = None
      freedIndices = i::freedIndices
    }

    // covariant node that helps keep track of the previous index of the stack
    private class StackNode[+S](val previousIndex: Int, val value: S)

  }
}

The code works like its suppose to if I call stack1.push or stack1.pop but it causes type mismatches on wrappers push1 and pop1, why is this happenning? 如果我调用stack1.push或stack1.pop,代码就像它假设的那样,但它会导致包装器push1和pop1上的类型不匹配,为什么会发生这种情况?

example for push1: 
type mismatch;
 found   : value.type (with underlying type A)
 required: A
  def push1[A](value :A): Unit = stack1.push(value)

example for pop1: 
type mismatch;
 found   : Option[A(in class ThreeStacks)]
 required: Option[A(in method pop1)]
 def pop1[A](): Option[A] = stack1.pop()

The problem in your code is type parameter shadowing. 代码中的问题是类型参数阴影。

You have: 你有:

class ThreeStacks[A, B, C](val stackSize:Int  = 1000) {
  def push1[A](value: A): Unit = stack1.push(value)
  ...
}

It should be: 它应该是:

class ThreeStacks[A, B, C](val stackSize:Int  = 1000) {
  def push1(value: A): Unit = stack1.push(value)
  ...
}

The way you have done it, type parameter A of class ThreeStacks and type parameter A of method push1 are completely different ones and thus, are incompatible with each other. 你做了它的方式,类型参数A类的ThreeStacks和类型参数的A方法的push1是完全不同的人,因此,彼此不兼容。 The same applies to B and C . 这同样适用于BC

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM