Во-первых, вы должны знать, что в scala { block; of; code }
это выражение, которое оценивается независимо от того, что оценивает последнее выражение внутри.
Когда вы говорите:
fun(i => { println("hi"); println(i) })
создать анонимную функцию, которая содержит корпус 2 выражения, как возвращение ()
и оба вычисляются, когда функция вызывается, все, как и ожидалось.
Но когда вы говорите
fun({println("hi"); println(_)})
Вы передаете в блоке, не анонимную функцию. Как пояснил sepp2k это расширяется
{ println("hi"); x => println(x) }
Таким образом, вы передаете блок fun
, этот блок оценивается, прежде чем он будет принят. Итак, первый println("hi")
происходит, он печатается только один раз, когда блок оценивается один раз, а затем оценивается этот x => println(x)
, который является функцией Int => Unit
, которая печатает свой аргумент. Это и только это (в качестве последнего выражения передается fun
. Именно поэтому каждый раз, когда вы вызываете fun
, он просто печатает аргумент дважды.
Чтобы увидеть дальше, как блок может работать, вы можете посмотреть на этом примере, что делает более в блоке
fun {
println("building the function")
val uuidOfThisFunction = UUID.randomUUID
x => println(s"$uuidOfThisFunction, $x")
}
Так что этот блок готовит функцию, придавая ему некоторый дополнительный контекст через закрытие. Этот uuid останется неизменным для обоих вызовов, которые произойдут, если fun
.
building the function
86e74b5e-83b5-41f3-a71c-eeafcd1db2a0, 10
86e74b5e-83b5-41f3-a71c-eeafcd1db2a0, 20
Пример, который будет выглядеть как то, что вы сделали с первым звонком будет
fun(
x => {
println("calling the function")
val uuidOfThisCall = UUID.randomUUID
println(s"$uuidOfThisCall, $x")
}
)
Блок оценивает каждый раз, когда f
называется.
calling the function
d3c9ff0a-84b4-47a3-8153-c002fa16d6c2, 10
calling the function
a0b1aa5b-c0ea-4047-858b-9db3d43d4983, 20
Я думаю, что вы просто дали описание результата, а не причину. Как определение 'def fun (f: Int => Unit)', что такое 'f' в определении' fun {println ("hi"); println (_)} '? если 'println (" hi ")' не включен в 'f', почему? – Jerry
Да, это то, что я действительно хочу знать. Фактически, я хочу реализовать эффект вызова метода 1, между тем я хочу просто вызвать «fun (i => {println (« hi »); println (i)})». Поэтому я использовал вызов метода 2, но найти эффект сильно отличается от вызова метода 1. Поэтому я хочу получить реальную причину, почему println («привет») не входит в f в вызове метода 2? – lagom
@atline Я считаю, что я дал настоящую причину. '{Println ("привет"); println (_)} 'не расширяется до' {x => {println ("hi"); println (x)}} ', а скорее' {println ("hi"); x => println (x)} '. Вот почему вы видите поведение, которое видите. Причина, по которой он расширяется, заключается в том, что правила расширения довольно просты. Для этого случая соответствующее правило просто состоит в том, что 'f (args ..., _, ... moreArgs)' расширяется до 'x => f (args ..., _, ... moreArgs)'. Если вы хотите знать, почему правила такие, как они есть, вы можете спросить дизайн, но это, вероятно, сводится к тому, что простые правила, как правило, лучше, нужно смотреть на ... – sepp2k