Làm thế nào để bạn trở về từ một chức năng tại một điểm tùy ý?


12

Làm thế nào để bạn trở về sớm từ một chức năng trước khi nó kết thúc? Ví dụ:

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

Câu trả lời:


19

Chúng tôi có một số tùy chọn có sẵn.

Phi

Bạn có thể catch/ throwđể thoát khỏi chức năng.

thí dụ:

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

Khối

Bạn cũng có thể sử dụng blockreturn-from(mặc dù bạn sẽ cần phải yêu cầu cl-macs)

thí dụ:

(require 'cl-macs)

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

cl-defun

Chúng ta cũng có cl-defunmột hàm ẩn blockcó cùng tên với hàm, vì vậy chúng ta có thể thực hiện blockkiểu với ít hơn.

thí dụ:

(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-defuncũng có sẵn như một bí danh defun*được định nghĩa trong 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
Lưu ý rằng nếu bạn không có ưu tiên cho cú pháp CL, catch/ throwcó nhiều thành ngữ hơn trong elisp, vì các cách tiếp cận khác cuối cùng được thực hiện theo cách bắt / ném. Hướng dẫn elisp nói: "Hầu hết các phiên bản khác của Lisp, bao gồm Common Lisp, có nhiều cách chuyển kiểm soát nonsequentially: return, return-from, và go., Ví dụ Emacs Lisp chỉ có throw."
phils

5

Ngoài những gì @EmacsFodder bảo hiểm, chỉ cần đưa ra một lỗi.

Điều này sẽ không hữu ích nếu mã được gọi bên trong (một cách linh hoạt, không phải từ vựng) phạm vi của các cấu trúc xử lý lỗi như ignore-errorshoặc condition-case, nhưng nếu không thì đó là một cách tốt để thoát khỏi hàm. Đó là thực tế những gì được thực hiện hầu hết thời gian.

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

Nếu bạn muốn tự xử lý lỗi thì bạn có thể đặt mã cuộc gọi (ví dụ như cuộc gọi đến một cái gì đó mà gọi my-funcmột cách sâu sắc ) bên trong a condition-case. Một lần nữa, đây là những gì được thực hiện hầu hết thời gian, ít nhất là thường xuyên như sử dụng catch+ throw. Tất cả phụ thuộc vào hành vi bạn muốn.


Cảm ơn câu trả lời của Drew, tôi đồng ý đây là một phương pháp khá phổ biến. Tuy nhiên, chỉ cần hoàn trả sớm bằng nhiều ngôn ngữ khác, sẽ không gây ra sự phức tạp khi phải xử lý lỗi. Khi nghiên cứu bộ câu hỏi / câu trả lời. Tôi đặc biệt tìm kiếm các lựa chọn thay thế cho phong cách "lỗi" mà luôn cảm thấy khó chịu với tôi. Tôi đã không xác định rõ ràng điều này trong văn bản câu hỏi tâm trí bạn.
ocodo

1
Tất cả phụ thuộc vào những gì bạn muốn làm. Nếu bạn muốn kết thúc ngay lập tức, không xử lý / xử lý thêm, thì việc đưa ra lỗi là một cách tốt để tìm lối thoát không nhắm mục tiêu, trong Emacs. Nếu bạn muốn làm một cái gì đó trong một lối thoát không nhắm mục tiêu, nghĩa là, xử lý nó theo một cách nào đó catch, sau đó unwind-protect, condition-casevà tương tự là hữu ích. Có cả một phần của hướng dẫn Elisp dành cho lối thoát hiểm không nhắm mục tiêu . (Và không có gì đặc biệt về bất kỳ ai trong số họ, IMO.)
vẽ

"Cảm thấy" là hoàn toàn chủ quan của khóa học. Cảm ơn các ref thủ công không nhắm mục tiêu.
ocodo
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.