为什么使用可变参数的重载方法会导致 StackOverflowError?
Why does overloaded method using varargs cause StackOverflowError?
我用一个重载方法实现了一个 Scala class,该方法可以接受一个 Iterable[String]
或一个 String*
可变参数:
class Whosebug(names: Iterable[String]) {
// This function creates a copy of the Whosebug object
// copy is needed but this cannot be a case class.
private def copy(names: Iterable[String] = names) = new Whosebug(names) // <- line 19
// overloaded methods
def withNames(names: Iterable[String]) = this.copy(names = names) // <- line 24
def withNames(names: String*) = require(names.nonEmpty); withNames(names.toIterable) // <- line 26
}
object App {
def main(args: Array[String]) = {
val x1 = new Whosebug(Seq("a", "b"))
val x2 = x1.withNames("c", "d")
}
}
我希望 x2
成为名称为 c
和 d
的新对象,但无法创建值 x2
,因为无限递归导致 WhosebugError :
Exception in thread "main" java.lang.WhosebugError
at scala.collection.LinearSeqLike$class.thisCollection(LinearSeqLike.scala:48)
at scala.collection.immutable.List.thisCollection(List.scala:84)
at scala.collection.immutable.List.thisCollection(List.scala:84)
at scala.collection.IterableLike$class.toIterable(IterableLike.scala:87)
at scala.collection.AbstractIterable.toIterable(Iterable.scala:54)
at test.Whosebug.<init>(Whosebug.scala:26)
at test.Whosebug.copy(Whosebug.scala:19)
at test.Whosebug.withNames(Whosebug.scala:24)
at test.Whosebug.<init>(Whosebug.scala:26)
at test.Whosebug.copy(Whosebug.scala:19)
at test.Whosebug.withNames(Whosebug.scala:24)
...
代码有什么问题?
你被大括号的遗漏所困。
您甚至不需要 val x2 = x1.withNames("c", "d")
行。
def withNames(names: String*) = require(names.nonEmpty); withNames(names.toIterable)
这实际上是:
def withNames(names: String*) = require(names.nonEmpty) // part of class
withNames(names.toIterable) // part of constructor
withNames(names.toIterable)
绝对正确,因为 names
也是您 class.
中的一个字段
因此,无论何时实例化 Whosebug 对象,构造函数都会调用 withNames()
创建新实例,然后调用 withNames()
等等。要解决此问题,您必须在方法定义周围使用大括号。当然,由于您正在重载 withNames() ,因此您还必须指定 return 类型。
我用一个重载方法实现了一个 Scala class,该方法可以接受一个 Iterable[String]
或一个 String*
可变参数:
class Whosebug(names: Iterable[String]) {
// This function creates a copy of the Whosebug object
// copy is needed but this cannot be a case class.
private def copy(names: Iterable[String] = names) = new Whosebug(names) // <- line 19
// overloaded methods
def withNames(names: Iterable[String]) = this.copy(names = names) // <- line 24
def withNames(names: String*) = require(names.nonEmpty); withNames(names.toIterable) // <- line 26
}
object App {
def main(args: Array[String]) = {
val x1 = new Whosebug(Seq("a", "b"))
val x2 = x1.withNames("c", "d")
}
}
我希望 x2
成为名称为 c
和 d
的新对象,但无法创建值 x2
,因为无限递归导致 WhosebugError :
Exception in thread "main" java.lang.WhosebugError
at scala.collection.LinearSeqLike$class.thisCollection(LinearSeqLike.scala:48)
at scala.collection.immutable.List.thisCollection(List.scala:84)
at scala.collection.immutable.List.thisCollection(List.scala:84)
at scala.collection.IterableLike$class.toIterable(IterableLike.scala:87)
at scala.collection.AbstractIterable.toIterable(Iterable.scala:54)
at test.Whosebug.<init>(Whosebug.scala:26)
at test.Whosebug.copy(Whosebug.scala:19)
at test.Whosebug.withNames(Whosebug.scala:24)
at test.Whosebug.<init>(Whosebug.scala:26)
at test.Whosebug.copy(Whosebug.scala:19)
at test.Whosebug.withNames(Whosebug.scala:24)
...
代码有什么问题?
你被大括号的遗漏所困。
您甚至不需要 val x2 = x1.withNames("c", "d")
行。
def withNames(names: String*) = require(names.nonEmpty); withNames(names.toIterable)
这实际上是:
def withNames(names: String*) = require(names.nonEmpty) // part of class
withNames(names.toIterable) // part of constructor
withNames(names.toIterable)
绝对正确,因为 names
也是您 class.
因此,无论何时实例化 Whosebug 对象,构造函数都会调用 withNames()
创建新实例,然后调用 withNames()
等等。要解决此问题,您必须在方法定义周围使用大括号。当然,由于您正在重载 withNames() ,因此您还必须指定 return 类型。