ฉันคิดว่ามี@tailrec
คำอธิบายประกอบเพื่อให้แน่ใจว่าคอมไพเลอร์จะปรับแต่งฟังก์ชันหางซ้ำให้เหมาะสม คุณเอาไว้หน้าใบประกาศหรือไม่? ยังใช้งานได้หรือไม่หากใช้ Scala ในโหมดสคริปต์ (เช่นใช้:load <file>
ภายใต้ REPL)
ฉันคิดว่ามี@tailrec
คำอธิบายประกอบเพื่อให้แน่ใจว่าคอมไพเลอร์จะปรับแต่งฟังก์ชันหางซ้ำให้เหมาะสม คุณเอาไว้หน้าใบประกาศหรือไม่? ยังใช้งานได้หรือไม่หากใช้ Scala ในโหมดสคริปต์ (เช่นใช้:load <file>
ภายใต้ REPL)
คำตอบ:
จากบล็อกโพสต์" Tail Calling, @tailrec และ trampolines ":
- ใน Scala 2.8 คุณจะสามารถใช้
@tailrec
คำอธิบายประกอบใหม่เพื่อรับข้อมูลเกี่ยวกับวิธีการที่เหมาะสมที่สุด
คำอธิบายประกอบนี้ให้คุณทำเครื่องหมายวิธีการเฉพาะที่คุณหวังว่าคอมไพเลอร์จะปรับให้เหมาะสม
จากนั้นคุณจะได้รับคำเตือนหากคอมไพเลอร์ไม่ได้รับการปรับให้เหมาะสม- ใน Scala 2.7 หรือก่อนหน้าคุณจะต้องพึ่งพาการทดสอบด้วยตนเองหรือการตรวจสอบ bytecode เพื่อดูว่ามีการปรับวิธีการให้เหมาะสมหรือไม่
ตัวอย่าง:
คุณสามารถเพิ่ม
@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 - รหัสจะทำงานโดยไม่มีมัน แต่ถ้าคุณใส่ไว้ที่นั่นมันจะบอกคุณว่าคุณทำผิดหรือไม่