Câu trả lời:
Từ bài đăng trên blog " Đuôi gọi, @tailrec và trampolines ":
- Trong Scala 2.8, bạn cũng sẽ có thể sử dụng
@tailrec
chú thích mới để nhận thông tin về các phương pháp được tối ưu hóa.
Chú thích này cho phép bạn đánh dấu các phương pháp cụ thể mà bạn hy vọng trình biên dịch sẽ tối ưu hóa.
Sau đó, bạn sẽ nhận được cảnh báo nếu chúng không được trình biên dịch tối ưu hóa.- Trong Scala 2.7 hoặc phiên bản cũ hơn, bạn sẽ cần phải dựa vào kiểm tra thủ công hoặc kiểm tra mã bytecode, để tìm ra phương pháp đã được tối ưu hóa hay chưa.
Thí dụ:
bạn có thể thêm
@tailrec
chú thích để có thể chắc chắn rằng các thay đổi của mình đã hoạt động.
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)
}
}
Và nó hoạt động từ REPL (ví dụ từ các mẹo và thủ thuật 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 = {
^
Trình biên dịch Scala sẽ tự động tối ưu hóa bất kỳ phương thức đệ quy đuôi thực sự nào. Nếu bạn chú thích một phương thức mà bạn tin là đệ quy đuôi với @tailrec
chú thích, thì trình biên dịch sẽ cảnh báo bạn nếu phương thức thực sự không đệ quy đuôi. Điều này làm cho @tailrec
chú thích trở thành một ý tưởng tốt, vừa để đảm bảo rằng một phương pháp hiện có thể được tối ưu hóa và nó vẫn có thể tối ưu hóa khi nó được sửa đổi.
Lưu ý rằng Scala không coi một phương thức là đệ quy đuôi nếu nó có thể bị ghi đè. Do đó, phương thức phải là private, cuối cùng, trên một đối tượng (trái ngược với một lớp hoặc đặc điểm), hoặc bên trong một phương thức khác để được tối ưu hóa.
Chú thích là scala.annotation.tailrec
. Nó gây ra lỗi trình biên dịch nếu phương thức không thể được tối ưu hóa cuộc gọi đuôi, điều này xảy ra nếu:
Nó được đặt ngay trước def
định nghĩa phương thức trong. Nó hoạt động trong REPL.
Ở đây chúng tôi nhập chú thích và cố gắng đánh dấu một phương thức là @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 {
^
Giáo sư! Lời kêu gọi cuối cùng là 1.+()
, không phải length()
! Hãy định dạng lại phương pháp:
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
Lưu ý rằng length0
nó tự động là private vì nó được định nghĩa trong phạm vi của một phương thức khác.
override
chú thích trong Java - mã hoạt động mà không cần nó, nhưng nếu bạn đặt nó ở đó, nó sẽ cho bạn biết nếu bạn mắc lỗi.