【问题标题】:Why does overloaded method using varargs cause StackOverflowError?为什么使用可变参数的重载方法会导致 StackOverflowError?
【发布时间】:2015-01-12 05:58:08
【问题描述】:

我实现了一个带有重载方法的 Scala 类,该方法可以采用 Iterable[String]String* 可变参数:

class StackOverflow(names: Iterable[String]) {

  // This function creates a copy of the StackOverflow object
  // copy is needed but this cannot be a case class.
  private def copy(names: Iterable[String] = names) = new StackOverflow(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 StackOverflow(Seq("a", "b"))
    val x2 = x1.withNames("c", "d")
  }
}

我希望 x2 是一个名为 cd 的新对象,但由于无限递归导致 StackOverflowError,无法创建值 x2

Exception in thread "main" java.lang.StackOverflowError
    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.StackOverflow.<init>(StackOverflow.scala:26)
    at test.StackOverflow.copy(StackOverflow.scala:19)
    at test.StackOverflow.withNames(StackOverflow.scala:24)
    at test.StackOverflow.<init>(StackOverflow.scala:26)
    at test.StackOverflow.copy(StackOverflow.scala:19)
    at test.StackOverflow.withNames(StackOverflow.scala:24)
    ...

代码有什么问题?

【问题讨论】:

    标签: scala variadic-functions


    【解决方案1】:

    你被大括号的遗漏困住了。

    您甚至不需要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 也是您班级中的一个字段。

    因此,每当您实例化 StackOverflow 对象时,构造函数都会调用 withNames() 创建一个新实例,然后调用 withNames() 等等。要解决此问题,您必须在方法定义周围使用大括号。当然,由于您要重载 withNames(),因此您还必须指定返回类型。

    【讨论】:

    • 更改后,我还注意到String*Iterable[String]Seq[String] 有点不兼容。
    • @NicolaFerraro 你是什么意思?
    • 编译器现在抱怨withNames的两个版本具有相同的擦除。如果我使用 List[String] 没有问题。
    • @NicolaFerraro stackoverflow.com/questions/7040382/… 这个问题澄清了您对 Seq 和 varargs 的问题。
    猜你喜欢
    • 2023-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多