인수를 취하지 않고 값을 반환하지 않는 함수를 나타내려고합니다 (알아야하는 경우 JavaScript에서 setTimeout 함수를 시뮬레이션하고 있습니다).
case class Scheduled(time : Int, callback : => Unit)
“val”매개 변수가 이름별로 호출되지 않을 수 있습니다 “라고 컴파일하지 않습니다.
case class Scheduled(time : Int, callback : () => Unit)
컴파일하지만 대신 이상하게 호출해야합니다.
Scheduled(40, { println("x") } )
나는 이것을해야한다
Scheduled(40, { () => println("x") } )
작동하는 것은
class Scheduled(time : Int, callback : Unit => Unit)
그러나 똑같이 합리적인 방식으로 호출됩니다
Scheduled(40, { x : Unit => println("x") } )
(Unit 유형의 변수는 무엇입니까?) 물론 원하는 것은 일반적인 함수 인 경우 호출하는 방식을 호출 할 수있는 생성자입니다.
Scheduled(40, println("x") )
아기에게 병을 줘!
답변
이름 별 전화 : => 유형
이 => Type
표기법은 이름 별 호출을 나타내며 매개 변수를 전달할 수있는 많은 방법 중 하나입니다 . 익숙하지 않다면 요즘 위키 백과 기사를 읽어 보는 것이 좋습니다. 요즘은 대부분의 가치 별 기준이며 기준 별 기준입니다.
의미는 전달 된 것이 함수 내부의 값 이름으로 대체 된다는 것입니다 . 예를 들어 다음 기능을 사용하십시오.
def f(x: => Int) = x * x
이렇게 전화하면
var y = 0
f { y += 1; y }
그런 다음 코드는 다음과 같이 실행됩니다
{ y += 1; y } * { y += 1; y }
식별자 이름 충돌이 발생하면 어떤 일이 발생하는지 지적합니다. 기존의 이름 별 통화에서는 이름 충돌을 피하기 위해 캡처 방지 대체라는 메커니즘이 사용됩니다. 그러나 Scala에서는 동일한 결과로 다른 방식으로 구현됩니다. 매개 변수 내의 식별자 이름은 호출 된 함수의 식별자를 참조하거나 섀도 잉 할 수 없습니다.
다른 두 가지를 설명한 후에 언급 할 이름 별 통화와 관련된 몇 가지 다른 점이 있습니다.
0-arity 함수 : () => Type
구문 () => Type
은의 유형을 나타냅니다 Function0
. 즉, 매개 변수를 사용하지 않고 무언가를 반환하는 함수입니다. 이는 메서드를 호출하는 것과 같습니다 size()
. 매개 변수를 사용하지 않고 숫자를 반환합니다.
그러나이 구문은 익명 함수 리터럴 의 구문과 매우 유사하다는 점이 흥미 롭습니다. 이는 혼동의 원인이됩니다. 예를 들어
() => println("I'm an anonymous function")
arity 0의 익명 함수 리터럴이며 유형 은
() => Unit
그래서 우리는 쓸 수 있습니다 :
val f: () => Unit = () => println("I'm an anonymous function")
그러나 유형과 값을 혼동하지 않는 것이 중요합니다.
단위 => 유형
이것은 실제로 단지 Function1
첫 번째 매개 변수 유형 Unit
입니다. 작성하는 다른 방법은 (Unit) => Type
또는 Function1[Unit, Type]
입니다. 문제는 … 이것이 원하는 것이 아닐 것입니다. Unit
유형의 주요 목적은 그래서 이해가되지 않습니다에 관심되지 않은 값을 표시한다 받을 그 값을.
예를 들어,
def f(x: Unit) = ...
무엇을 할 수 x
있습니까? 단일 값만 가질 수 있으므로받을 필요가 없습니다. 가능한 함수 중 하나는 다음을 반환하는 체인 함수입니다 Unit
.
val f = (x: Unit) => println("I'm f")
val g = (x: Unit) => println("I'm g")
val h = f andThen g
에 andThen
정의되어 Function1
있고 우리가 연결하는 함수가 반환되고 있기 때문에이를 연결 시킬 수 Unit
있는 유형으로 정의해야 Function1[Unit, Unit]
했습니다.
혼란의 근원
혼동의 첫 번째 원인은 0-arity 함수에 존재하는 유형과 리터럴의 유사성이 이름 별 호출에도 존재한다고 생각하는 것입니다. 다시 말해,
() => { println("Hi!") }
의 리터럴입니다 () => Unit
.
{ println("Hi!") }
의 리터럴이됩니다 => Unit
. 그렇지 않습니다. 그것은 리터럴이 아닌 코드 블록입니다 .
혼동의 또 다른 원인은 Unit
type 값 이 ()
0-arity 매개 변수 목록처럼 보이지만 그렇지 않다는 것입니다.
답변
case class Scheduled(time : Int, callback : => Unit)
case
수정 암시한다 val
생성자에 각 인수의 아웃. 따라서 (누군가 지적했듯이) 제거 case
하면 이름 별 호출 매개 변수를 사용할 수 있습니다. 컴파일러는 어쨌든 허용 할 수 있지만 val callback
로 변형하는 대신 생성하면 사람들을 놀라게 할 수 있습니다 lazy val callback
.
callback: () => Unit
지금 변경하면 이름 별 호출 매개 변수 대신 함수가 사용됩니다. 분명히 함수를 저장할 수 있으므로 val callback
아무런 문제가 없습니다.
원하는 것을 얻는 가장 쉬운 방법은 ( Scheduled(40, println("x") )
이름 별 호출 매개 변수를 사용하여 람다를 전달하는 경우) 아마도 건너 뛰고 처음에는 얻을 수없는 것을 case
명시 적으로 만드는 것 apply
입니다.
class Scheduled(val time: Int, val callback: () => Unit) {
def doit = callback()
}
object Scheduled {
def apply(time: Int, callback: => Unit) =
new Scheduled(time, { () => callback })
}
사용:
scala> Scheduled(1234, println("x"))
res0: Scheduled = Scheduled@5eb10190
scala> Scheduled(1234, println("x")).doit
x
답변
이 질문에서는 JavaScript로 SetTimeOut 함수를 시뮬레이션하려고합니다. 이전 답변을 바탕으로 다음 코드를 작성합니다.
class Scheduled(time: Int, cb: => Unit) {
private def runCb = cb
}
object Scheduled {
def apply(time: Int, cb: => Unit) = {
val instance = new Scheduled(time, cb)
Thread.sleep(time*1000)
instance.runCb
}
}
REPL에서는 다음과 같은 것을 얻을 수 있습니다.
scala> Scheduled(10, println("a")); Scheduled(1, println("b"))
a
b
시뮬레이션은 함수를 차단하지만 SetTimeOut은 비 차단이기 때문에 시뮬레이션은 SetTimeOut과 정확히 동일하게 동작하지 않습니다.
답변
나는 이런 식으로한다 (단지 적용하고 싶지 않다) :
case class Thing[A](..., lazy: () => A) {}
object Thing {
def of[A](..., a: => A): Thing[A] = Thing(..., () => a)
}
전화 해
Thing.of(..., your_value)