Tách không gian tên Clojure trên nhiều tệp


91

Có thể chia không gian tên Clojure trên nhiều tệp nguồn khi thực hiện biên dịch trước thời hạn với :gen-classkhông? Làm thế nào để (:main true)(defn- ...)đi vào chơi?

Câu trả lời:


137

Tổng quat

Chắc chắn bạn có thể, trên thực tế, clojure.corechính không gian tên được chia theo cách này và cung cấp một mô hình tốt mà bạn có thể theo dõi bằng cách xem trong src/clj/clojure:

core.clj
core_deftype.clj
core_print.clj
core_proxy.clj
..etc..

Tất cả các tệp này tham gia để xây dựng clojure.corekhông gian tên duy nhất .

Tệp chính

Một trong số này là tệp chính, được đặt tên khớp với tên không gian tên để nó sẽ được tìm thấy khi ai đó đề cập đến nó trong dấu :usehoặc :require. Trong trường hợp này, tệp chính là clojure/core.clj, và nó bắt đầu bằng một nsbiểu mẫu. Đây là nơi bạn nên đặt tất cả cấu hình không gian tên của mình, bất kể tệp nào khác của bạn có thể cần chúng. Điều này thường cũng bao gồm :gen-class, vì vậy một cái gì đó như:

(ns my.lib.of.excellence
  (:use [clojure.java.io :as io :only [reader]])
  (:gen-class :main true))

Sau đó, tại những vị trí thích hợp trong tệp chính của bạn (phổ biến nhất là ở cuối) sử dụng loadđể đưa vào tệp trợ giúp của bạn. Trong clojure.corenó trông như thế này:

(load "core_proxy")
(load "core_print")
(load "genclass")
(load "core_deftype")
(load "core/protocols")
(load "gvec")

Lưu ý rằng bạn không cần thư mục hiện tại làm tiền tố, cũng như không cần .cljhậu tố.

Tệp trợ giúp

Mỗi tệp trợ giúp phải bắt đầu bằng cách khai báo không gian tên nào mà chúng đang trợ giúp, nhưng nên làm như vậy bằng cách sử dụng in-nshàm. Vì vậy, đối với không gian tên ví dụ ở trên, tất cả các tệp trợ giúp sẽ bắt đầu bằng:

(in-ns 'my.lib.of.excellence)

Đó là tất cả những gì nó cần.

lớp gen

Bởi vì tất cả các tệp này đang xây dựng một không gian tên duy nhất, mỗi hàm bạn xác định có thể nằm trong bất kỳ tệp chính hoặc tệp trợ giúp nào. Tất nhiên, điều này có nghĩa là bạn có thể xác định các gen-classchức năng của mình trong bất kỳ tệp nào bạn muốn:

(defn -main [& args]
  ...)

Lưu ý rằng các quy tắc xác định thứ tự thông thường của Clojure vẫn áp dụng cho tất cả các hàm, vì vậy bạn cần đảm bảo rằng bất kỳ tệp nào xác định một hàm đều được tải trước khi bạn cố gắng sử dụng hàm đó.

Vars riêng

Bạn cũng đã hỏi về (defn- foo ...)biểu mẫu xác định một không gian tên-chức năng riêng tư. Các hàm được xác định như vậy cũng như các :privatevars khác có thể nhìn thấy từ bên trong không gian tên nơi chúng được xác định, vì vậy các tệp chính và tất cả các tệp trợ giúp sẽ có quyền truy cập vào các vars riêng tư được xác định trong bất kỳ tệp nào được tải cho đến nay.


3
Rất hay, câu trả lời đầy đủ! BTW, tôi sắp hoàn thành chuyến đi đầu tiên của mình qua The Joy of Clojure . Cuốn sách tuyệt vời!
Ralph

Cảm ơn vì đã chia sẻ câu trả lời này. Nó có được coi là một thực hành tốt vẫn còn, 2 năm sau? (Tôi biết mọi thứ thay đổi nhanh chóng.) Tôi thấy rằng bản thân Clojure vẫn sử dụng kỹ thuật này.
David J.

9
Cho đến ngày nay, đây vẫn là phương pháp hay nhất nếu bạn chắc chắn muốn nhiều tệp để tạo một không gian tên duy nhất. Tuy nhiên, bản thân nó có thể ít phổ biến hơn bây giờ. Một giải pháp thay thế có thể là xác định tất cả các vars công khai của ns của bạn trong một tệp duy nhất và di chuyển tất cả các vars trợ giúp và các chức năng sang một vùng tên "triển khai" riêng biệt. Về mặt kỹ thuật, các vars trong impl sẽ được công khai, nhưng một chuỗi doc ns chỉ ra rằng chúng không phải là một phần của API được lập thành văn bản là phổ biến và cần phải đủ.
Chouser

1
Chúng tôi có biết liệu có bất kỳ công cụ Clojure thông thường nào có vấn đề khi hiểu không gian tên nhiều tệp không? Lein? Khởi động? Rượu táo? nREPL? Kibit? Eastwood? Che giấu? Vv ...
Didier A.
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.