Tải lại đang Clojure sử dụng (require … :reload)
và :reload-all
là rất có vấn đề :
Nếu bạn sửa đổi hai không gian tên phụ thuộc lẫn nhau, bạn phải nhớ tải lại chúng theo đúng thứ tự để tránh lỗi biên dịch.
Nếu bạn xóa định nghĩa khỏi tệp nguồn và sau đó tải lại, các định nghĩa đó vẫn có sẵn trong bộ nhớ. Nếu mã khác phụ thuộc vào các định nghĩa đó, nó sẽ tiếp tục hoạt động nhưng sẽ phá vỡ lần sau khi bạn khởi động lại JVM.
Nếu không gian tên được tải lại chứa defmulti
, bạn cũng phải tải lại tất cả các defmethod
biểu thức liên quan .
Nếu không gian tên được tải lại chứa defprotocol
, bạn cũng phải tải lại bất kỳ bản ghi hoặc loại nào thực hiện giao thức đó và thay thế bất kỳ phiên bản hiện có nào của các bản ghi / loại đó bằng các phiên bản mới.
Nếu không gian tên được tải lại chứa macro, bạn cũng phải tải lại bất kỳ không gian tên nào sử dụng các macro đó.
Nếu chương trình đang chạy chứa các hàm đóng trên các giá trị trong không gian tên được tải lại, các giá trị đóng đó sẽ không được cập nhật. (Điều này là phổ biến trong các ứng dụng web xây dựng "ngăn xếp xử lý" như là một thành phần của các chức năng.)
Thư viện clojure.tools.namespace cải thiện đáng kể tình hình. Nó cung cấp một chức năng làm mới dễ dàng, tải lại thông minh dựa trên biểu đồ phụ thuộc của các không gian tên.
myapp.web=> (require '[clojure.tools.namespace.repl :refer [refresh]])
nil
myapp.web=> (refresh)
:reloading (myapp.web)
:ok
Thật không may, tải lại lần thứ hai sẽ thất bại nếu không gian tên mà bạn tham chiếu refresh
hàm thay đổi. Điều này là do thực tế là tools.namespace phá hủy phiên bản hiện tại của không gian tên trước khi tải mã mới.
myapp.web=> (refresh)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: refresh in this context, compiling:(/private/var/folders/ks/d6qbfg2s6l1bcg6ws_6bq4600000gn/T/form-init819543191440017519.clj:1:1)
Bạn có thể sử dụng tên var đủ điều kiện để khắc phục sự cố này nhưng cá nhân tôi không muốn phải gõ tên đó trên mỗi lần làm mới. Một vấn đề khác ở trên là sau khi tải lại không gian tên chính, các hàm trợ giúp REPL tiêu chuẩn (như doc
và source
) không còn được tham chiếu ở đó nữa.
Để giải quyết các vấn đề này, tôi thích tạo một tệp nguồn thực tế cho không gian tên người dùng để nó có thể được tải lại một cách đáng tin cậy. Tôi đặt tập tin nguồn vào ~/.lein/src/user.clj
nhưng bạn có thể đặt ở bất cứ đâu. Tệp phải yêu cầu chức năng làm mới trong khai báo ns hàng đầu như thế này:
(ns user
(:require [clojure.tools.namespace.repl :refer [refresh]]))
Bạn có thể thiết lập hồ sơ người dùng leiningen trong ~/.lein/profiles.clj
vì vậy vị trí mà bạn đặt các tập tin trong được thêm vào đường dẫn lớp. Hồ sơ sẽ trông giống như thế này:
{:user {:dependencies [[org.clojure/tools.namespace "0.2.7"]]
:repl-options { :init-ns user }
:source-paths ["/Users/me/.lein/src"]}}
Lưu ý rằng tôi đặt không gian tên người dùng làm điểm vào khi khởi chạy REPL. Điều này đảm bảo rằng các hàm trợ giúp REPL được tham chiếu trong không gian tên người dùng thay vì không gian tên chính của ứng dụng của bạn. Bằng cách đó, họ sẽ không bị mất trừ khi bạn thay đổi tệp nguồn chúng tôi vừa tạo.
Hi vọng điêu nay co ich!
(use 'foo.bar :reload-all)
luôn luôn làm việc tốt cho tôi Ngoài ra,(load-file)
không bao giờ cần thiết nếu bạn có đường dẫn lớp được thiết lập đúng. "Hiệu ứng bắt buộc" bạn không nhận được là gì?