Почему этот код компилируется и выдает ошибку времени выполнения при выполнении - PullRequest
3 голосов
/ 15 января 2020

Этот код Scala компилируется в Scala 2.13

val res = new scala.collection.mutable.StringBuilder
"hello".foreach { c =>
  if (true) {
    (0 until 10).foreach( res += c )
  }
}

Если вы видите, что в методе foreach отсутствует аргумент для анонимной функции. Когда он выполняется, он выдает исключение StringIndexOutOfBoundsException для res += c, что вызывает недоумение, поскольку StringBuilder всегда должен быть добавляемым.

Следующий код работает нормально, исключений нет. Единственное изменение - добавление _ в качестве заполнителя для foreach функции параметра:

val res = new scala.collection.mutable.StringBuilder()
"hello".foreach { c =>
  if (true) {
    (0 until 10).foreach( _ => res += c )
  }
}

Ответы [ 2 ]

5 голосов
/ 15 января 2020

Ответ на ваш вопрос лежит в String.apply() или StringBuilder.apply(), если быть более точным.

Видите ли, foreach ожидает функцию. В более точных словах, выражение, которое оценивает функцию.

Итак, сначала он вычислит выражение для получения функции, затем применяет эту функцию для 0 until 10

, поэтому при рассмотрении первой итерации внешнего foreach вы получаете c = 'h' и далее,

(0 until 10).foreach(res += c )

Здесь res += c вернет res после добавления к нему h.

Итак ... оцененная функция равна res или res.apply с res = "h". Следовательно, вышесказанное на самом деле,

(0 until 10).foreach("h".apply)

Итак, res.apply(0) идет хорошо ... но res.apply(1) не удается с StringIndexOutOfBoundsException.

0 голосов
/ 15 января 2020

Пожалуйста, смотрите подпись для

def foreach[U](f: A => U): Unit = {
}

(f: A => U)  this is a function, not an expression.

...