내 사용 사례가 더 복잡하지만, 기본적으로 아래 내가 달성하기 위해 노력하고있는 무슨의 간단한 예입니다 (내 원래 코드는 akka 스트림입니다) :꼬리 재귀 (@tailrec) 재귀 함수 대 비 재귀 함수 스칼라 스택 오버플로 오류?
offset := 0
//pump data
def pump(): Unit = {
elem := poller.getNumberFromOffset(offset)
elem match {
case null => doSomething()
case Completed => doSomethingElse()
case _ =>
offset += 1
//check if the element is matched with a pre-supplied selector/filter function
if(filterFunc(elem)) {
doSomething2()
} else {
//if the element doesn't match; increase offset and try again; can sleep for a while here
pump()
}
}
}
문제는 그 펌프() 함수 수도있다 스택 오버 플로우가 발생합니다 (펌프 기능이 특정 조건에 대해 반복적으로 호출되기 때문에).
나는 다음과 같은 비 재귀 버전으로 기능을 쓸 수:
이offset := 0
//pump data
def pump(): Unit = {
elem := poller.getNumberFromOffset(offset)
while(elem != null && elem != Completed && !filterFunc(elem)) {
offset += 1
elem = poller.getNumberFromOffset(offset)
}
elem match {
case null => doSomething()
case Completed => doSomethingElse()
case _ =>
offset += 1
doSomething2()
}
}
그러나 내 사용 사례는 훨씬 더 복잡하다; 그래서 기존 코드를 while/for 루프로 변환하는 대신 가능한 경우 재귀 함수를 사용하고 싶습니다.
첫 번째 예제에 @tailrec 주석을 넣으면 scala 컴파일러가 펌프를 tail-recursion 함수 (@tailrec def pump())로 처리하기 때문에 제 질문에 "그렇게해야합니까?"라는 질문이 있습니다. 단위 = {}). 필자의 경우, pump() 함수는 고정 간격으로 분리하여 호출해야합니다. 그래서 스택 프레임은 실제로 여기서 필요하지 않습니다.
감사합니다.
"첫 번째 예제에'@ tailrec' 주석을 단순히 붙이면 어떤 차이가 있습니다. '- @ tailrec' 주석은 아무런 차이가 없습니다. Tail-recursive 메서드는 항상 최적화되어 있습니다. (좀더 정확히 말하자면 : [spec에 제시된 조건을 만족시키는] 메소드 (http://scala-lang.org/files/archive/spec/2.13/06-expressions.html#function-applications).) 유일한 것은 메소드가 tail-recursive가 아닌 경우'@ tailrec' 주석은 컴파일러 오류를 생성합니다. [방법이 최적화되었는지 여부는 * 변경하지 않습니다.] –
패턴 일치에 대해 'null'에 도전합니다. 대신, [Option # apply] (http://www.scala-lang.org/api/2.11.8/index.html#[email protected] [A]())에서 가능한 'null'값을 래핑합니다. x : A) : 옵션 [A]). 예 :'Option [String] {null}'==='None' –