@tailrec
컴파일러가 꼬리 재귀 함수를 최적화 할 수 있도록 주석 이 있다고 생각 합니다. 선언문 앞에 그냥 두세요? Scala가 스크립팅 모드 (예 :load <file>
: REPL 에서 사용)에서 사용되는 경우에도 작동합니까 ?
답변:
" Tail calls, @tailrec 및 trampolines "블로그 게시물에서 :
- Scala 2.8에서는 새로운
@tailrec
주석을 사용하여 최적화 된 메서드에 대한 정보를 얻을 수도 있습니다 .
이 주석을 사용하면 컴파일러가 최적화 할 특정 메서드를 표시 할 수 있습니다.
그런 다음 컴파일러에 의해 최적화되지 않은 경우 경고가 표시됩니다.- Scala 2.7 또는 이전 버전에서는 메서드가 최적화되었는지 여부를 확인하기 위해 수동 테스트 또는 바이트 코드 검사에 의존해야합니다.
예:
@tailrec
변경 사항이 제대로 작동하는지 확인할 수 있도록 주석을 추가 할 수 있습니다.
import scala.annotation.tailrec
class Factorial2 {
def factorial(n: Int): Int = {
@tailrec def factorialAcc(acc: Int, n: Int): Int = {
if (n <= 1) acc
else factorialAcc(n * acc, n - 1)
}
factorialAcc(1, n)
}
}
그리고 REPL에서 작동합니다 ( Scala REPL 팁과 트릭의 예 ).
C:\Prog\Scala\tests>scala
Welcome to Scala version 2.8.0.RC5 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_18).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import scala.annotation.tailrec
import scala.annotation.tailrec
scala> class Tails {
| @tailrec def boom(x: Int): Int = {
| if (x == 0) throw new Exception("boom!")
| else boom(x-1)+ 1
| }
| @tailrec def bang(x: Int): Int = {
| if (x == 0) throw new Exception("bang!")
| else bang(x-1)
| }
| }
<console>:9: error: could not optimize @tailrec annotated method: it contains a recursive call not in tail position
@tailrec def boom(x: Int): Int = {
^
<console>:13: error: could not optimize @tailrec annotated method: it is neither private nor final so can be overridden
@tailrec def bang(x: Int): Int = {
^
Scala 컴파일러는 진정한 꼬리 재귀 방법을 자동으로 최적화합니다. 꼬리 재귀 적이라고 생각되는 메서드에 주석을 달면 @tailrec
컴파일러는 메서드가 실제로 꼬리 재귀 적이 지 않은지 경고합니다. 이렇게하면 @tailrec
메서드가 현재 최적화 가능하고 수정 될 때도 최적화 가능한 상태로 유지되도록하는 주석이 좋은 아이디어가됩니다.
Scala는 재정의 할 수있는 경우 메서드를 꼬리 재귀로 간주하지 않습니다. 따라서 메서드는 개인, 최종, 객체 (클래스 또는 특성과 반대) 또는 최적화 할 다른 메서드 내부에 있어야합니다.
주석은입니다 scala.annotation.tailrec
. 메서드가 테일 호출을 최적화 할 수없는 경우 컴파일러 오류를 트리거합니다.
def
메서드 정의에서 바로 앞에 배치 됩니다. REPL에서 작동합니다.
여기에서 주석을 가져오고 메소드를 @tailrec
.
scala> import annotation.tailrec
import annotation.tailrec
scala> @tailrec def length(as: List[_]): Int = as match {
| case Nil => 0
| case head :: tail => 1 + length(tail)
| }
<console>:7: error: could not optimize @tailrec annotated method: it contains a recursive call not in tail position
@tailrec def length(as: List[_]): Int = as match {
^
이런! 마지막 호출은 1.+()
하지 length()
! 방법을 재구성 해 보겠습니다.
scala> def length(as: List[_]): Int = {
| @tailrec def length0(as: List[_], tally: Int = 0): Int = as match {
| case Nil => tally
| case head :: tail => length0(tail, tally + 1)
| }
| length0(as)
| }
length: (as: List[_])Int
참고 length0
이 다른 방법의 범위에 정의되어 있기 때문에 자동으로 비공개입니다.
override
Java 의 주석 과 비슷 하다고 생각합니다. 코드는 코드 없이도 작동하지만 거기에 넣으면 실수를했는지 알려줍니다.