Tour of Scala

Конструкция Автоматического Замыкания Зависимого Типа

Language

Scala допускает использование в качестве параметров методов имена беспараметрических функций. При вызове такого метода фактические параметры для беспараметрических функций не вычисляются, а передается функция с нулем аргументов, которая захватывает вычисление соответствующего параметра (так называемый вызов по имени).

Следующий код демонстрирует этот механизм:

object TargetTest1 extends Application {
  def whileLoop(cond: => Boolean)(body: => Unit): Unit =
    if (cond) {
      body
      whileLoop(cond)(body)
    }
  var i = 10
  whileLoop (i > 0) {
    println(i)
    i -= 1
  }
}

Функция whileLoop принимает два параметра cond и body. При использовании функции значения этих параметров не вычисляются. Но всякий раз, когда параметры используются в теле whileLoop, их значение будет вычисляться заново через использование автоматически созданных неявно вызываемых функций. Таким образом, наш метод whileLoop реализует Java-подобный цикл while-loop со схемой рекурсивной реализации.

Мы можем комбинировать использование инфиксных/постфиксных операторов с этим механизмом для создания более сложных выражений (с хорошим синтаксисом).

Вот реализация loop-unless выражения:

object TargetTest2 extends Application {
  def loop(body: => Unit): LoopUnlessCond =
    new LoopUnlessCond(body)
  protected class LoopUnlessCond(body: => Unit) {
    def unless(cond: => Boolean) {
      body
      if (!cond) unless(cond)
    }
  }
  var i = 10
  loop {
    println("i = " + i)
    i -= 1
  } unless (i == 0)
} Функция `loop` принимает только тело цикла и возвращает экземпляр класса `LoopUnlessCond` (который захватывает это тело цикла). Обратите внимание, что тело еще не вычислено. Класс `LoopUnlessCond` имеет метод `unless`, который мы можем использовать как *инфиксный оператор*. Таким образом, мы получаем вполне естественный синтаксис для нашего нового цикла: `loop { < выражение > } unless ( < условие > )`.

Ниже приведен вывод выполнения TargetTest2:

i = 10
i = 9
i = 8
i = 7
i = 6
i = 5
i = 4
i = 3
i = 2
i = 1

Contributors to this page: