Có một số lý do tại sao một người không nên sử dụng EVAL
.
Lý do chính cho người mới bắt đầu là: bạn không cần nó.
Ví dụ (giả sử Lisp chung):
ĐÁNH GIÁ một biểu thức với các toán tử khác nhau:
(let ((ops '(+ *)))
(dolist (op ops)
(print (eval (list op 1 2 3)))))
Điều đó tốt hơn được viết là:
(let ((ops '(+ *)))
(dolist (op ops)
(print (funcall op 1 2 3))))
Có rất nhiều ví dụ mà người mới bắt đầu học Lisp nghĩ rằng họ cần EVAL
, nhưng họ không cần nó - vì các biểu thức được đánh giá và người ta cũng có thể đánh giá phần chức năng. Hầu hết thời gian sử dụngEVAL
cho thấy sự thiếu hiểu biết của người đánh giá.
Đây là vấn đề tương tự với các macro. Thông thường người mới bắt đầu viết macro, nơi họ nên viết các hàm - không hiểu macro thực sự là gì và không hiểu rằng một hàm đã thực hiện công việc.
Nó thường là công cụ sai cho công việc sử dụng EVAL
và nó thường chỉ ra rằng người mới bắt đầu không hiểu các quy tắc đánh giá Lisp thông thường.
Nếu bạn nghĩ rằng bạn cần EVAL
, sau đó kiểm tra nếu một cái gì đó như FUNCALL
, REDUCE
hoặc APPLY
có thể được sử dụng thay thế.
FUNCALL
- gọi một hàm với các đối số: (funcall '+ 1 2 3)
REDUCE
- gọi một hàm trên danh sách các giá trị và kết hợp các kết quả: (reduce '+ '(1 2 3))
APPLY
- gọi một hàm với một danh sách là các đối số : (apply '+ '(1 2 3))
.
Q: Tôi thực sự cần eval hay trình biên dịch / đánh giá đã là những gì tôi thực sự muốn?
Những lý do chính cần tránh EVAL
đối với người dùng cao cấp hơn một chút:
bạn muốn chắc chắn rằng mã của bạn được biên dịch, bởi vì trình biên dịch có thể kiểm tra mã cho nhiều vấn đề và tạo mã nhanh hơn, đôi khi RẤT NHIỀU (đó là yếu tố 1000 ;-)) mã nhanh hơn
mã được xây dựng và cần được đánh giá không thể được biên dịch sớm nhất có thể.
eval của đầu vào người dùng tùy ý mở ra các vấn đề bảo mật
một số sử dụng đánh giá có EVAL
thể xảy ra không đúng lúc và tạo ra các vấn đề xây dựng
Để giải thích điểm cuối cùng với một ví dụ đơn giản:
(defmacro foo (a b)
(list (if (eql a 3) 'sin 'cos) b))
Vì vậy, tôi có thể muốn viết một macro dựa trên tham số đầu tiên sử dụng SIN
hoặcCOS
.
(foo 3 4)
làm (sin 4)
và (foo 1 4)
làm(cos 4)
.
Bây giờ chúng ta có thể có:
(foo (+ 2 1) 4)
Điều này không cho kết quả mong muốn.
Người ta có thể muốn sửa chữa macro FOO
bằng cách ĐÁNH GIÁ biến:
(defmacro foo (a b)
(list (if (eql (eval a) 3) 'sin 'cos) b))
(foo (+ 2 1) 4)
Nhưng sau đó, điều này vẫn không hoạt động:
(defun bar (a b)
(foo a b))
Giá trị của biến chỉ là không biết tại thời điểm biên dịch.
Một lý do quan trọng chung để tránh EVAL
: nó thường được sử dụng cho các hack xấu xí.