Это называется параметром по имени , что относится к стратегии оценки параметров по имени.Пожалуйста, смотрите в связанной статье в Википедии похожие, но не идентичные способы передачи параметров.
Чтобы объяснить это лучше, давайте сначала рассмотрим две наиболее распространенные стратегии оценки параметров: вызов по значению и вызов по ссылке.
Call by value - безусловно, самая распространенная стратегия оценки.Это единственная стратегия в Java, например, и стратегия по умолчанию в C. Рассмотрим, например, эту простую Java-программу:
public class ByValue {
static public void inc(int y) {
y++;
}
static public void main(String... args) {
int x = 0;
inc(x);
System.out.println(x);
}
}
Она напечатает 0
, потому что x
значение копируется в y
, поэтому при увеличении y
исходное значение в x
не изменяется.Сравните это с этой программой на C ++ с помощью вызова по ссылке:
#include <stdio.h>
void inc(int &y) {
y++;
}
int main() {
int x = 0;
inc(x);
printf("%d\n", x);
}
Это выведет 1
, потому что ссылка на x передается inc
вместо *Значение 1022 *.
Обратите внимание, что Java передает ссылки на объекты по значению, что заставляет некоторых утверждать, что он вызывает по ссылке.Это не так, если вы назначите объект new параметру функции, это не будет отражено в вызывающей функции.
Итак, что делаетвызов по имени выглядит?При вызове по имени не передается ни значение, ни ссылка.Вместо этого передается весь код , и везде, где используется параметр, выполняется код и используется его результат.Например:
object ByName {
def incIfZero(y: => Int): Int = if (y == 0) y + 1 else y
def main(args: Array[String]) {
var x = 0
x = incIfZero( { val tmp = x; x += 1; tmp } )
println(x)
}
}
В этом примере печатается 2
вместо 1
, поскольку блок кода, переданный в качестве параметра, оценивается дважды.При выполнении это выглядит так, как будто вторая строка в main
была написана так:
x = if ({ val tmp = x; x += 1; tmp }) { val tmp = x; x += 1; tmp } + 1 else { val tmp = x; x += 1; tmp }
Теперь параметры по имени имеют как минимум три интересных применения:
- Этоможет использоваться для задержки выполнения чего-либо до надлежащего времени.
- Может использоваться для избегать выполнения в некоторых ситуациях.
- Может использоваться для выполнениянесколько блоков кода несколько раз.
Первый и последний случаи, я думаю, довольно очевидны.Вот пример второго случая:
implicit def fromBoolean(b: Boolean) = new {
def and(that: => Boolean): Boolean = if (b) that else b }
val x = 0
(x > 0) and (10 / x > 0)
Если бы that
не был параметром по имени, в последней строке было бы исключение.Как это, он просто вернет false
.