내가 알기로, 스칼라에서 함수는
- 값별 또는
- 이름으로
예를 들어, 다음과 같은 선언에서 함수가 어떻게 호출되는지 알고 있습니까?
선언:
def f (x:Int, y:Int) = x;
요구
f (1,2)
f (23+55,5)
f (12+3, 44*11)
규칙은 무엇입니까?
답변
제시 한 예제는 값별 호출 만 사용하므로 차이점을 보여주는 새롭고 간단한 예제를 제공합니다.
먼저 부작용이있는 함수가 있다고 가정 해 봅시다. 이 함수는 무언가를 출력 한 다음를 반환합니다 Int
.
def something() = {
println("calling something")
1 // return value
}
이제 우리는 Int
하나의 값을 호출하는 스타일 ( x: Int
)로, 다른 하나는 이름을 부르는 스타일 ( )로 인수를 취하는 것을 제외하고는 정확히 동일한 인수 를 받아들이는 두 함수를 정의 할 것입니다 x: => Int
.
def callByValue(x: Int) = {
println("x1=" + x)
println("x2=" + x)
}
def callByName(x: => Int) = {
println("x1=" + x)
println("x2=" + x)
}
이제 부작용 기능으로 호출하면 어떻게됩니까?
scala> callByValue(something())
calling something
x1=1
x2=1
scala> callByName(something())
calling something
x1=1
calling something
x2=1
따라서 값별 호출 버전에서는 전달 된 함수 호출 ( something()
) 의 부작용 이 한 번만 발생 했음을 알 수 있습니다 . 그러나 이름 별 통화 버전에서는 부작용이 두 번 발생했습니다.
값별 호출 함수는 함수를 호출하기 전에 전달 된 표현식의 값을 계산하므로 매번 동일한 값에 액세스하기 때문입니다. 대신, 이름 별 호출 함수 는 전달 될 때마다 전달 된 표현식의 값을 재 계산 합니다.
답변
다음은 Martin Odersky의 예입니다.
def test (x:Int, y: Int)= x*x
다음과 같은 조건에서 평가 전략을 검토하고 어느 단계가 더 빠른지 (더 적은 단계) 결정합니다.
test (2,3)
값으로 호출 : test (2,3)-> 2 * 2-> 4
이름으로 호출 : test (2,3)-> 2 * 2-> 4
여기서 동일한 단계 수로 결과에 도달합니다.
test (3+4,8)
값으로 전화 : test (7,8)-> 7 * 7-> 49
이름으로 전화 : (3 + 4) (3 + 4)-> 7 (3 + 4)-> 7 * 7-> 49
여기에 전화 값이 빠릅니다.
test (7,2*4)
값으로 전화 : test (7,8)-> 7 * 7-> 49
이름으로 전화 : 7 * 7-> 49
여기에서 이름으로 전화하는 것이 더 빠릅니다
test (3+4, 2*4)
값으로 호출 : test (7,2 * 4)-> test (7, 8)-> 7 * 7-> 49
이름으로 호출 : (3 + 4) (3 + 4)-> 7 (3 + 4) -> 7 * 7-> 49
같은 단계에서 결과에 도달합니다.
답변
예제의 경우 모든 매개 변수는 value 로만 정의 하기 때문에 함수에서 호출 되기 전에 평가 됩니다 . 이름으로 매개 변수를 정의 하려면 코드 블록을 전달해야합니다.
def f(x: => Int, y:Int) = x
이런 식으로 매개 변수 x
는 함수에서 호출 될 때까지 평가되지 않습니다 .
여기 의이 작은 포스트 는 이것도 잘 설명해줍니다.
답변
위의 의견에서 @Ben의 요점을 반복하려면 “이름 별 전화”를 구문 설탕으로 생각하는 것이 가장 좋습니다. 파서는 표현식을 익명 함수로 래핑하여 나중에 사용될 때 호출 할 수 있도록합니다.
사실상, 정의하는 대신
def callByName(x: => Int) = {
println("x1=" + x)
println("x2=" + x)
}
그리고 달리기 :
scala> callByName(something())
calling something
x1=1
calling something
x2=1
당신은 또한 쓸 수 있습니다 :
def callAlsoByName(x: () => Int) = {
println("x1=" + x())
println("x2=" + x())
}
같은 효과를 얻으려면 다음과 같이 실행하십시오.
callAlsoByName(() => {something()})
calling something
x1=1
calling something
x2=1
답변
예제를 제공하는 것이 아니라 간단한 사용 사례로 설명하려고합니다.
시간이 지날수록 매번 잔소리 되는 “비틀 거림 앱” 을 만들고 싶다고 상상해보십시오 .
다음 구현을 조사하십시오.
object main {
def main(args: Array[String]) {
def onTime(time: Long) {
while(time != time) println("Time to Nag!")
println("no nags for you!")
}
def onRealtime(time: => Long) {
while(time != time) println("Realtime Nagging executed!")
}
onTime(System.nanoTime())
onRealtime(System.nanoTime())
}
}
위의 구현에서 Nagger는 이름으로 전달할 때만 작동합니다. 이유는 값으로 전달할 때 다시 사용되므로 이름으로 전달할 때마다 값이 다시 평가되지 않고 값이 다시 평가되지 않기 때문입니다. 변수에 액세스 한 시간
답변
일반적으로 함수에 대한 매개 변수는 값별 매개 변수입니다. 즉, 매개 변수 값은 함수에 전달되기 전에 결정됩니다. 그러나 함수 내에서 호출 될 때까지 평가하고 싶지 않은 표현식을 매개 변수로 받아들이는 함수를 작성해야하는 경우 어떻게해야합니까? 이러한 상황에서 Scala는 이름 별 호출 매개 변수를 제공합니다.
이름 별 호출 메커니즘은 코드 블록을 수신자에게 전달하고 수신자가 매개 변수에 액세스 할 때마다 코드 블록이 실행되고 값이 계산됩니다.
object Test {
def main(args: Array[String]) {
delayed(time());
}
def time() = {
println("Getting time in nano seconds")
System.nanoTime
}
def delayed( t: => Long ) = {
println("In delayed method")
println("Param: " + t)
t
}
}
1. C : /> scalac Test.scala 2. 스칼라 테스트 3. 지연된 방법 4. 나노초로 시간 얻기 5. 매개 변수 : 81303808765843 6. 나노초로 시간 얻기
답변
내가 가정 call-by-value
한 것처럼 위에서 설명한 함수는 값을 함수에 전달합니다. 에 따르면 Martin Odersky
이 기능 평가에서 중요한 역할을 스칼라에 의한 평가 전략의 후속이다. 그러나 간단하게하십시오 call-by-name
. 그것과 마찬가지로 함수를 메소드의 인수로 전달하는 것으로도 알려져 Higher-Order-Functions
있습니다. 메소드가 전달 된 매개 변수의 값에 액세스 할 때 전달 된 함수의 구현을 호출합니다. 아래:
@dhg 예제에 따르면, 먼저 다음과 같이 메소드를 작성하십시오.
def something() = {
println("calling something")
1 // return value
}
이 함수는 하나의 println
명령문을 포함 하고 정수 값을 리턴합니다. 다음과 같은 인수를 가진 함수를 작성하십시오 call-by-name
.
def callByName(x: => Int) = {
println("x1=" + x)
println("x2=" + x)
}
이 함수 매개 변수는 하나의 정수 값을 반환하는 익명 함수를 정의합니다. 여기 x
에는0
인수를 전달했지만 반환 int
값과 something
함수에 동일한 서명 포함됩니다. 함수를 호출하면에 함수를 인수로 전달합니다 callByName
. 그러나 call-by-value
그것 의 경우 정수 값을 함수에 전달합니다. 다음과 같이 함수를 호출합니다.
scala> callByName(something())
calling something
x1=1
calling something
x2=1
이 우리에서 something
우리의 가치를 액세스 할 때 때문에, 두 번 호출 방법 x
에 callByName
방법의 (고화질)과의 전화,something
방법.
