คุณจะกลับมาจากฟังก์ชั่นที่จุดใดก็ได้?


12

คุณจะกลับก่อนจากฟังก์ชั่นก่อนที่มันจะจบลงอย่างไร ตัวอย่างเช่น:

(defun my-func () 
 "for example."
 (unless something (return nil))
 ; continue as usual...
 (+ 42 1))

คำตอบ:


19

เรามีตัวเลือกมากมายให้เลือก

โยน

คุณสามารถcatch/ throwเพื่อออกจากฟังก์ชั่น

ตัวอย่าง:

(defun my-func ()
  "thrown error"
  (catch 'my-catch
    (when t
      (throw 'my-catch "always going to throw"))
    (+ 42 1)))

บล็อก

คุณยังสามารถใช้blockและreturn-from(แม้ว่าคุณจะต้องมีcl-macs)

ตัวอย่าง:

(require 'cl-macs)

(defun my-func ()
  "block / return-from"
  (block my-func
    (when t
      (return-from my-func))
    (+ 42 1)))

CL-defun

นอกจากนี้เรายังมีcl-defunสิ่งที่มีความหมายโดยนัยที่blockมีชื่อเดียวกับฟังก์ชั่นเพื่อให้เราสามารถทำblockรูปแบบที่มีน้อย

ตัวอย่าง:

(require 'cl-macs)

(cl-defun my-func ()
  "cl-defun implicit block"
  (when t
    (return-from my-func)) ; my-func is an implicit block.
  (+ 42 1)))

defun *

cl-defunยังมีอยู่ในนามแฝงdefun*ที่กำหนดไว้ในcl.el:

(require 'cl)

(defun* my-func ()
  "defun* implicit block"
  (when t
    (return-from my-func)) ; my-func is an implicit block.
  (+ 42 1)))

4
โปรดทราบว่าหากคุณไม่มีการกำหนดค่าตามความชอบสำหรับไวยากรณ์ CL catch/ throwเป็นสำนวนที่มากกว่าใน elisp เนื่องจากวิธีการอื่น ๆ จะถูกนำไปใช้ในที่สุดในแง่ของการจับ / โยน คู่มือ Elisp กล่าวว่า "รุ่นอื่น ๆ ส่วนใหญ่ชัดรวมทั้งธรรมดาชัดมีหลายวิธีในการถ่ายโอนการควบคุม nonsequentially: return, return-fromและgo. เช่น Emacs เสียงกระเพื่อมมีเพียงthrow."
phils

5

นอกเหนือจากสิ่งที่ @EmacsFodder ครอบคลุมเพียงแค่เพิ่มข้อผิดพลาด

สิ่งนี้จะไม่ช่วยถ้ารหัสถูกเรียกใช้ภายใน (แบบไดนามิกไม่เกี่ยวกับคำศัพท์) ขอบเขตของโครงสร้างการจัดการข้อผิดพลาดเช่นignore-errorsหรือcondition-caseแต่อย่างอื่นมันเป็นวิธีที่ดีในการออกจากฟังก์ชัน ในความเป็นจริงสิ่งที่ทำส่วนใหญ่เวลา

(defun my-func () 
 "..."
 (unless something (error "Whoops!"))
 ; continue as usual...
 (+ 42 1))

หากคุณต้องการที่จะจัดการกับข้อผิดพลาดด้วยตัวคุณเองแล้วคุณสามารถใส่รหัสโทร (เช่นการเรียกร้องให้สิ่งที่โทร ulimately my-func) condition-caseภายใน อีกครั้งนี้เป็นสิ่งที่จะทำมากที่สุดของเวลาอย่างน้อยได้บ่อยเท่าที่ใช้+catch throwทุกอย่างขึ้นอยู่กับพฤติกรรมที่คุณต้องการ


ขอบคุณสำหรับคำตอบ Drew ฉันยอมรับว่านี่เป็นวิธีการทั่วไป อย่างไรก็ตามเพียงแค่ทำการคืนต้นในภาษาอื่น ๆ จำนวนมากไม่ได้เกิดความซับซ้อนในการจัดการกับข้อผิดพลาดนั้น เมื่อทำการวิจัยชุดคำถาม / คำตอบ ฉันกำลังมองหาทางเลือกโดยเฉพาะกับสไตล์ "ข้อผิดพลาด" ซึ่งมักทำให้ฉันรู้สึกขี้เกียจ ฉันไม่ได้ระบุสิ่งนี้อย่างชัดเจนในใจความของคำถาม
ocodo

1
ทุกอย่างขึ้นอยู่กับสิ่งที่คุณต้องการจะทำ หากคุณต้องการที่จะจบลงทันทีโดยไม่มีการประมวลผล / การจัดการเพิ่มเติมจากนั้นการเพิ่มข้อผิดพลาดเป็นวิธีที่ดีในการออกจาก nonlocal ใน Emacs หากคุณต้องการที่จะทำบางสิ่งบางอย่างในระหว่างการออกจากต่างแดนคือจัดการกับมันอย่างนั้นcatch, unwind-protect, condition-caseและชอบที่มีประโยชน์ มีทั้งส่วนของคู่มือ Elisp ที่อุทิศให้กับการออกนอกสถานที่ (และไม่มีอะไรพิเศษโดยเฉพาะอย่างยิ่งเกี่ยวกับพวกเขา IMO.)
ดึง

"Feels" เป็นอัตนัยทั้งหมดแน่นอน ขอบคุณสำหรับการอ้างอิงแบบไม่ใช้คนในท้องถิ่น
ocodo
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.