不考虑方法参数的默认值
Default value for method parameter is not considered
我已经在 "Empty" 案例对象以及 "Top" 案例 class 中为参数 "currentStack" 提供了默认值,但是如果我在调用推送方法我收到以下消息
"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 方法,它可以添加一个元素。一旦我尝试通过进一步的推送调用添加另一个元素,我就会收到上述错误消息。
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)
}
所以,总结一下。问题是,即使在你的两个子 类 中,你已经覆盖了 push
方法以获得默认值。
trait 上的方法签名没有这样的默认值。而且,因为那是你调用的那个,编译器发出了正确的错误。
您可以进行模式匹配,以了解您拥有 Stack
中的哪个特定 case,这样编译器就会找到具有默认值的签名。但是,由于默认值始终是 Stack
,其形状与 this 相同,并且您真正需要的只是使用 this (因为作为不可变集合,可以有结构共享),不如只重写方法
下面是你的Stack
的实现,比较简洁(恕我直言).
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]
我已经在 "Empty" 案例对象以及 "Top" 案例 class 中为参数 "currentStack" 提供了默认值,但是如果我在调用推送方法我收到以下消息
"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 方法,它可以添加一个元素。一旦我尝试通过进一步的推送调用添加另一个元素,我就会收到上述错误消息。
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)
}
所以,总结一下。问题是,即使在你的两个子 类 中,你已经覆盖了 push
方法以获得默认值。
trait 上的方法签名没有这样的默认值。而且,因为那是你调用的那个,编译器发出了正确的错误。
您可以进行模式匹配,以了解您拥有 Stack
中的哪个特定 case,这样编译器就会找到具有默认值的签名。但是,由于默认值始终是 Stack
,其形状与 this 相同,并且您真正需要的只是使用 this (因为作为不可变集合,可以有结构共享),不如只重写方法
下面是你的Stack
的实现,比较简洁(恕我直言).
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]