不考虑方法参数的默认值

时间:2019-04-21 21:52:38

标签: scala methods default-value

我已经为“ Empty”案例对象以及“ Top”案例类提供了参数“ currentStack”的默认值,但是如果在调用push方法时省略了参数,则会收到以下消息

"error: not enough arguments for method push: (newTop
: A, currentStack: Main.Stack[A])Main.Stack[A].
Unspecified value parameter currentStack.
                    currentBracket == '{') isBracketingValid(rest, bracketStack.push(currentBracket))".

我尝试构造一个空堆栈以及一个已经填充的堆栈,并在其上调用push方法以添加一个元素。尝试通过进一步的push调用添加另一个元素时,我得到了以上错误消息。

lazy val s1 = Empty

println(s1.push(1)) // <- works

//println(s1.push(1).push(2)) <- doesn't work

lazy val s2 = Top(3, Top(4, Empty))

println(s2.push(1)) // <- works

//println(s2.push(1).push(2)) <- doesn't work

此处是堆栈定义:

sealed trait Stack[+A] {
    def push[A] (newTop: A, currentStack: Stack[A]): Stack[A] = ???

    def pop: (Option[A], Stack[A]) = ???
}

case object Empty extends Stack[Nothing] {
    override def push[A] (newTop: A, currentStack: Stack[A] = Empty): Stack[A] = Top(newTop, currentStack)

    override def pop: (Option[Nothing], Stack[Nothing]) = (None, Empty)
}

case class Top[A](val top: A, val rest: Stack[A]) extends Stack[A] {
    override def push[A] (newTop: A, currentStack: Stack[A] = Top(top, rest)): Stack[A] = Top(newTop, currentStack)

    override def pop: (Option[A], Stack[A]) = (Some(top), rest)
}

def isBracketingValid(bracketString: String): Boolean = {
    def isBracketingValid(bracketList: List[Char], bracketStack: Stack[Char]): Boolean = bracketList match {
        case Nil => bracketStack == Empty
        case currentBracket :: rest => {
            lazy val previousBracket = bracketStack.pop._1.getOrElse('$')

            lazy val isRestValid = isBracketingValid(rest, bracketStack.pop._2)

            if (currentBracket == '(' ||
                currentBracket == '[' ||
                currentBracket == '{') isBracketingValid(rest, bracketStack.push(currentBracket))
            else if (currentBracket == ')') previousBracket == '(' && isRestValid
            else if (currentBracket == ']') previousBracket == '[' && isRestValid
            else if (currentBracket == '}') previousBracket == '{' && isRestValid
            else false
        }
    }
    isBracketingValid(bracketString.toList, Empty)
}

编辑

在Luis提示使用“ this”之后,重写了Stack定义,所以没有,因为没有传入任何堆栈,所以不会引起上述问题,但是我仍然对理解原因感兴趣。

sealed trait Stack[+A] {
    def push[A] (newTop: A): Top[A] = ???

    def pop: (Option[A], Stack[A]) = ???
}

case object Empty extends Stack[Nothing] {
    override def push[A] (newTop: A): Top[A] = Top(newTop, this)

    override def pop: (Option[Nothing], Stack[Nothing]) = (None, Empty)
}

case class Top[A](val top: A, val rest: Stack[A]) extends Stack[A] {
    override def push[A] (newTop: A): Top[A] = Top(newTop, this.asInstanceOf[Stack[A]])

    override def pop: (Option[A], Stack[A]) = (Some(top), rest)
}

编辑2

由于Luis不使用“ asInstanceof”而是用较低的类型绑定来实现目标,因此重构了堆栈的定义。并检查了为什么案件总的来说应该是最终的。

sealed trait Stack[+A] {
    def push[B >: A] (newTop: B): Top[B] = ???

    def pop: (Option[A], Stack[A]) = ???
}

case object Empty extends Stack[Nothing] {
    override def push[A] (newTop: A): Top[A] = Top(newTop, this)

    override def pop: (Option[Nothing], Stack[Nothing]) = (None, Empty)
}

final case class Top[+A] (val top: A, val rest: Stack[A]) extends Stack[A] {
    override def push[B >: A] (newTop: B): Top[B] = Top(newTop, this)

    override def pop: (Option[A], Stack[A]) = (Some(top), rest)
}

1 个答案:

答案 0 :(得分:1)

因此,总结一下。问题是,即使在您的两个子类中,您也已重写push方法以使其具有默认值。
特征上的方法签名没有这样的默认值。而且,由于那是您要调用的那个,因此编译器发出了正确的错误。
您可以进行模式匹配,以了解您使用了Stack的哪个特定 case ,这样编译器就可以找到具有默认值的签名。但是,由于默认值始终是Stack,其形状与 this 相同,并且由于您真正需要的只是使用 this (自作为一个不可变的集合,您可以进行结构共享),最好重写该方法。

以下是您的Stack的实现,该实现更简洁,(IMHO)

sealed trait Stack[+A] {
  final def push[B >: A](newTop: B): Stack[B] =
    Top(newTop, this)

  final def pop: (Option[A], Stack[A]) = this match {
    case Top(top, rest) => (Some(top), rest)
    case Empty          => (None, Empty)
  }
}

final case class Top[+A](top: A, rest: Stack[A]) extends Stack[A]
case object Empty extends Stack[Nothing]