2010-09-01 100 views
5
  1. 命名空間的用途是什麼?命名空間是什麼?用法呢?

  2. 更重要的是,它們應該用作java中的對象(具有數據和函數的東西,並試圖實現封裝)?這個想法是遠遠不夠的嗎? :)

  3. 還是應該將它們用作java中的包?

  4. 或者他們應該更普遍地作爲模塊系統或什麼東西?

回答

7

既然你使用Clojure的標籤,我想你會在一個特定的Clojure回答感興趣:

是什麼名稱空間的目的是什麼?

Clojure的命名空間,Java包,哈斯克爾/ Python的/不管模塊......在一個非常高的水平,他們在相同的基本機制,其主要目的是爲了防止在不平凡的名稱衝突的所有不同的名字代碼庫。當然,每種解決方案都有自己的小小的曲折和怪癖,它們在給定的語言環境中是有意義的,而且在它之外是沒有意義的。這個答案的其餘部分將處理Clojure特有的曲折和怪癖。

甲Clojure的命名空間組瓦爾,其保持功能的容器(最常見的),所使用的編譯器生成的適當形式,通常與defmacro定義macroexpansions宏函數(功能;實際上它們只是定期的Clojure功能儘管它們在編譯器中註冊的方式有些不可思議),偶爾會有各種各樣的「全局參數」(例如,標準輸入的clojure.core/*in*),Atoms/Refs等。Clojure 1.2中引入的協議工具具有很好的屬性,協議由Vars支持,個別協議功能也是如此;這是協議提出解決表達問題的方法的關鍵(但這可能超出了本答案的範圍!)。

這意味着命名空間應該組合Vars,這些Vars是相關的。一般來說,創建命名空間是一種便宜的操作,所以在開發的早期階段使用單個命名空間是非常好的(並且確實很平常),然後當獨立的功能塊出現時,將這些命名空間納入其自己的命名空間,沖洗&重複...只有屬於公共API的部分需要事先在名稱空間之間進行分配(或者更確切地說:在穩定版本之前),因爲函數this-and-such存在於名稱空間中,當然這也是API的一部分。

更重要的是,它們應該用作java中的對象(具有數據和函數的東西,並試圖實現封裝)?這個想法是遠遠不夠的嗎? :)

通常,答案是否定的。如果你將它們作爲具有許多靜態方法,沒有實例方法,沒有公共構造函數並且通常沒有狀態的類來接近它們,你可能會得到一張離真相不太遠的圖片(儘管偶爾會有一些「類數據成員」 Vars持有Atoms/Refs);但可以說不試圖將Java-ish隱喻應用於Clojure習語並將名稱空間視爲一組函數等,而不是「一個擁有一組函數的類」或某種類似的東西。

這個通用規則有一個重要的例外:命名空間,其中包括:gen-classns表單。這些是爲了實現一個Java類,它可能稍後會被實例化,可能有實例方法和每個實例狀態等。請注意,:gen-class是一個互操作功能 - 純粹的Clojure代碼通常應該避免它。

還是應該將它們用作java中的包?

它們服務於一些相同的目的,包被設計用於服務(如上所述);然而,類比,雖然它確實存在,但並不是那麼有用,僅僅因爲組合在一起的東西(Java類)完全不像Clojure命名空間組合在一起的東西(Clojure Vars),各種「訪問級別」 (在Java中,{:private true}或不Clojure中private/package/public)的工作非常不同等

話雖這麼說,人們必須記得有命名空間和包/類居住在特定的軟件包之間一定的對應。名爲foo.bar的名稱空間在編譯時會在包foo中生成一個名爲bar的類;這尤其意味着,名稱空間名稱應該至少包含一個點,因爲所謂的單段名稱顯然會導致類放入「默認包」中,從而導致各種奇怪現象。 (例如。我覺得不可能有VisualVM的的探查通知單段的命名空間中定義的任何功能。)

此外,deftype/defrecord -created類型不駐留在命名空間。在定義了名稱空間foo.bar的文件中有一個(defrecord Foo [...] ...)表單在包foo.bar中創建一個名爲Foo的類。要從其他名稱空間使用Foo類型,必須從foo.bar包中刪除類Foo - :use/:require不起作用,因爲它們從名稱空間中提取Vars,而這些記錄/類型不是。

因此,在這種特殊情況下,Clojure程序員希望利用某些新語言功能需要注意的名稱空間和程序包之間存在某種對應關係。有些人發現,這給予了不屬於互操作領域的特性的「互操作性」(即使我們忘記了它們在JVM上實現平臺速度的作用,也是一個很好的抽象機制)並且在Clojure的某些將來的版本中肯定有可能取消這種風格,以便可以將deftype & Co.的名稱空間名稱/包名稱對應視爲實現細節。

或者他們應該更普遍地作爲一個模塊系統或什麼東西?

他們一個模塊系統,這確實是他們應該如何使用。

0

把它們想象成你的類的容器。如果您有構建字符串的助手類,並且您希望在業務層中使用它,則可以使用MyApp.Business.Helpers等名稱空間。這允許你的類被包含在感性的位置,所以當你或者其他一些引用你的代碼的人想要使它們成爲它們時,它們可以很容易地被定位。另一個例子,如果你想消耗你可能會使用類似SQL連接輔助類:

MyApp.Data.SqlConnectionHelper sqlHelper = new MyApp.Data.SqlConnectionHelper();

在現實中,你會使用「使用」的聲明,所以你就不需要完全限定命名空間只是爲了聲明變量。

保羅

2

在Java中的包有自己的命名空間,它提供的類的邏輯分組。它還有助於防止命名衝突。例如,在Java中,您會發現java.util.Date和java.sql.Date - 兩個具有相同名稱的不同類,它們的名稱空間不同。如果你嘗試導入一個java文件,你會發現它不會編譯。至少有一個版本需要使用它的顯式名稱空間。

1

從語言獨立的角度來看,命名空間是一種隔離事物的方法(即封裝在一個sens中)。這是一個更一般的概念(例如,請參閱xml命名空間)。您可以通過多種方式「創建」命名空間,具體取決於您使用的語言:軟件包,靜態類,模塊等。所有這些都爲它們包含的對象/數據/函數提供了名稱空間。這允許更好地組織代碼,隔離功能,傾向於更好的代碼重用和適應性(如封裝)。如「Python的禪」中所述,「命名空間是一個好點子 - 讓我們做更多這些! 。