การแบ่งเนมสเปซ Clojure บนไฟล์หลายไฟล์


91

เป็นไปได้ไหมที่จะแบ่งเนมสเปซ Clojure บนไฟล์ต้นฉบับหลายไฟล์เมื่อทำการคอมไพล์ล่วงหน้าด้วย:gen-class? ทำอย่างไร(:main true)และ(defn- ...)เข้ามามีบทบาทอย่างไร?

คำตอบ:


138

ภาพรวม

แน่นอนคุณสามารถในความเป็นจริงclojure.corenamespace ตัวเองจะถูกแยกออกมาด้วยวิธีนี้และให้เป็นแบบอย่างที่ดีที่คุณสามารถปฏิบัติตามโดยการค้นหาในsrc/clj/clojure:

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

ไฟล์ทั้งหมดเหล่านี้มีส่วนร่วมในการสร้างclojure.coreเนมสเปซเดียว

ไฟล์หลัก

หนึ่งในนั้นคือไฟล์หลักซึ่งตั้งชื่อให้ตรงกับชื่อเนมสเปซเพื่อที่จะพบเมื่อมีคนพูดถึงไฟล์นั้นใน:useหรือ:require. ในกรณีนี้ไฟล์หลักคือclojure/core.cljและเริ่มต้นด้วยnsแบบฟอร์ม นี่คือที่ที่คุณควรกำหนดค่าเนมสเปซทั้งหมดของคุณไม่ว่าไฟล์อื่น ๆ ของคุณจะต้องการไฟล์ใด ซึ่งโดยปกติจะรวมถึง:gen-classเช่นกันดังนั้นสิ่งที่ต้องการ:

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

จากนั้นในตำแหน่งที่เหมาะสมในไฟล์หลักของคุณ (โดยทั่วไปจะอยู่ท้ายสุด) loadเพื่อนำไฟล์ตัวช่วยของคุณเข้ามา ในclojure.coreลักษณะนี้:

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

โปรดทราบว่าคุณไม่จำเป็นต้องใช้ไดเร็กทอรีปัจจุบันเป็นคำนำหน้าและไม่ต้องการ.cljคำต่อท้าย

ไฟล์ตัวช่วย

ไฟล์ตัวช่วยแต่ละไฟล์ควรเริ่มต้นด้วยการประกาศว่ากำลังช่วยเนมสเปซใด แต่ควรทำโดยใช้in-nsฟังก์ชัน ดังนั้นสำหรับตัวอย่างเนมสเปซด้านบนไฟล์ตัวช่วยทั้งหมดจะขึ้นต้นด้วย:

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

นั่นคือทั้งหมดที่ต้องใช้

gen-class

เนื่องจากไฟล์เหล่านี้ทั้งหมดสร้างเนมสเปซเดียวแต่ละฟังก์ชันที่คุณกำหนดอาจอยู่ในไฟล์หลักหรือไฟล์ตัวช่วยใดก็ได้ แน่นอนว่าคุณสามารถกำหนดgen-classฟังก์ชันของคุณในไฟล์ใดก็ได้ที่คุณต้องการ:

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

โปรดทราบว่ากฎคำสั่งนิยามตามปกติของ Clojure ยังคงใช้กับฟังก์ชันทั้งหมดดังนั้นคุณต้องตรวจสอบให้แน่ใจว่าไฟล์ใดก็ตามที่กำหนดฟังก์ชันจะถูกโหลดก่อนที่คุณจะพยายามใช้ฟังก์ชันนั้น

Vars ส่วนตัว

คุณยังถามเกี่ยวกับ(defn- foo ...)แบบฟอร์มที่กำหนดฟังก์ชันเนมสเปซส่วนตัว ฟังก์ชันที่กำหนดเช่นนี้และ:privateตัวแปรอื่น ๆสามารถมองเห็นได้จากภายในเนมสเปซที่กำหนดไว้ดังนั้นไฟล์หลักและไฟล์ตัวช่วยทั้งหมดจะสามารถเข้าถึงตัวแปรส่วนตัวที่กำหนดไว้ในไฟล์ใด ๆ ที่โหลดจนถึงตอนนี้


3
ดีมากตอบครบ! BTW ฉันเสร็จเกือบผ่านครั้งแรกของฉันผ่านความสุขของ Clojure หนังสือยอดเยี่ยม!
Ralph

ขอบคุณสำหรับการแบ่งปันคำตอบนี้ ถือว่าเป็นแนวทางปฏิบัติที่ดีหรือไม่ 2 ปีต่อมา? (ฉันรู้ว่าสิ่งต่างๆเปลี่ยนแปลงเร็ว) ฉันเห็นว่า Clojure เองก็ยังคงใช้เทคนิคนี้อยู่
David J.

9
ณ วันนี้ยังคงเป็นแนวทางปฏิบัติที่ดีที่สุดหากคุณแน่ใจว่าต้องการให้หลายไฟล์สร้างเนมสเปซเดียว อย่างไรก็ตามตอนนี้อาจจะไม่ค่อยพบบ่อยกว่าที่เป็นอยู่ อีกทางเลือกหนึ่งคือการกำหนดตัวแปรสาธารณะทั้งหมดของ ns ของคุณในไฟล์เดียวและย้ายตัวช่วยและฟังก์ชันทั้งหมดไปยังเนมสเปซ "การใช้งาน" ที่แยกจากกัน ในทางเทคนิค vars in im จะเป็นแบบสาธารณะ แต่ ns docstring ที่ระบุว่าพวกเขาไม่ได้เป็นส่วนหนึ่งของ API ที่มีเอกสารเป็นเรื่องธรรมดาและควรจะเพียงพอ
Chouser

1
เราทราบหรือไม่ว่าการใช้เครื่องมือ Clojure ทั่วไปมีปัญหาในการทำความเข้าใจเนมสเปซหลายไฟล์ ลีน? บูต? ไซเดอร์? nREPL? คิบิต? อีสต์วูด? กานพลู? ฯลฯ ...
Didier A.
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.