名稱空間(namespace)是一種抽象的容器,它主要的功能是用來區隔同名的變數或程序。想像一下,如果在某個公司裡有一個桃園來的小明和一個台北來的小明,有一天老闆氣呼呼的走進來大喊「小明你明天不用來了」,這樣會造成什麼情況? 可能會讓其中一個無辜的小明嚇出心臟病吧!! 但是如果老闆改說「台北來的小明你明天不用來了」,這樣就不會錯殺良民了。名稱空間的功能是用來防止像這種因為同名而發生錯亂的狀況。它的原則就是,不同名稱空間裡面的變數和程序就算有相同的名稱,也會被當成是獨立的個體,彼此不會互相影響。這一篇文章介紹了名稱空間機制以及使用方法,另外也說明如何把程式拆成多個檔案的方法。
14.1 名稱空間
就像上面說的,名稱空間是一個非常重要的功能,尤其是在大型專案製作或是多人共同開發時更顯得重要,因為很難保証大家不會用到同名的變數或程序。Tcl提供一種階層式的名稱空間管理方法,最頂層是叫做「::」的名稱空間。它是一種全域性質的空間,有時候也叫全域名稱空間,常態下我們會把整個程式會共同用到的變數或程序放在這個空間裡。在全域之下你可以建立任意的名稱空間或更下層的名稱空間,只要遵守「建立下層空間時,上層必定要先存在」的原則就可以了。下面的命令在全域之下建立一個叫dai的名稱空間:::dai是指頂層之下的dai名稱空間。凡是放在這個名稱空間之下的項目(變數及程序),都會與其它名稱空間的項目有所區隔。如果建立名稱空間時不是由頂層開始,就表示新建立的空間是在目前的空間之下。例如,下面的例子在::dai之下再建立editor及player的空間:
執行完上面的範例執行後,你的程式裡就最少有「::」、「::dai」、「::dai::editor」及「::dai::player」等4個名稱空間了。其中「::」除了用來表示頂層名稱空間外,也用來當做階層的分隔符號。注意哦!! 如果說在執行namespace eval時指定的空間早就存在了,那麼Tcl會把後面大括號的程式當成是在該空間裡執行。
14.2 名稱空間變數
名稱空間變數是專屬某個名稱空間的變數,只要你沒有手動刪除它或是名稱空間沒有被刪除,這種變數會持續存在,直到程式執行結束。例如,下面的程式在::dai空間裡建立了專屬的name及birthday變數:variable的使用和set命令一樣,但不同的是set主要用來建立一般的變數,而variable則用來建立名稱空間的變數。一但建立成功,在同一個名稱空間裡,你就可以使用一般的方法來取用或設定它們的內容。
如果在不同的空間裡使用name或birthday程式會出錯。例如:
這個例子在::other空間嘗試使用::dai空間裡的birthday變數,結果產生了下面的錯誤訊息,而且程式被中斷了。
can't read "birthday": no such variable while executing "puts $birthday"
如果真的要存取別個空間裡的變數,那你需要在變數的名稱前冠上完整的名稱空間路徑。例如:
請注意程式的第6行,它的意思是birthday在::dai空間之下,由於指出了完整的路徑所以puts就不會找不到birthday變數了。
下面的例子可以用來測試,不同名稱空間裡的變數就算有一樣的名字也是不一樣的個體。
程式的第9~10行順便說明在頂層空間裡存取特定名稱空間變數的方法。
程式輸出:
戴小良 路人甲 戴小良 路人甲
§ 不在名稱空間裡的項目
一般的情況下,如果變數或是程序沒有被放在任何名稱空間裡,那它們都屬於頂層的名稱空間。
14.3 名稱空間程序
把程序定義在某個名稱空間裡的方法如下:注意程式的第6行,如果在某個空間要呼叫其它空間裡的程序,請使用完整的名稱空間路徑。如果是在同一個空間裡就不用加路徑了。
如果你想在程序裡使用同一個名稱空間之下的變數,請使用下面的方法:
程式的第5~6行用來指明name及birthday是屬於同一層的名稱空間變數。注意!! 這邊不用指定變數的值,若指定的話變數的內容會被重新設定。事實上,不使用variable來指明同層的名稱空間變數,一樣可以使用完整路徑的方法來取用那些變數。但使用variable指明的方式,可以讓接下來的程式少打一些字。
14.4 把程式拆成多個檔案
把程式中獨立的功能拆成獨立的檔案來撰寫是一個好習慣。在Tcl裡你可以用source命令來引入外部的程式檔案。假設下面的程式是一個要被引入的外部檔案:然後在下面的程式使用source把14-1.tcl引入,還偷用了14-1裡定義的功能。
注意哦!! 在執行14-2時你要想像source會把14-1.tcl裡的程式碼內嵌在第1行的位置。另外一個重點是,上面的兩個檔案要放在同一個目錄裡,或是要指定明確的檔案路徑,不然source會找不到14-1.tcl。
如果說外部檔案和目前程式採用的字元編碼不一樣,那你可以自己指定外部檔案的編碼:
14.5 其它命名空間命令
如果你想知道某個名稱空間有哪些下層空間,可以這樣做:這個例子會以清單的方式,輸出::dai空間下一層的所有子名稱空間。注意哦!! 只包含下一層而已,更下層的並不會被輸出。
如果你想要知道目前的名稱空間,可以這樣做:
如果你想要知道某個名稱空間是否存在,可以這樣做:
namespace exists判斷::dai空間是否存在,是的話回傳1,不是回傳0。
如果你想要取得某個名稱空間的上層空間,可以這樣做:
如果你想要刪除某個名稱空間,可以這樣做:
當你刪除名稱空間時,所有包含在該名稱空間裡的變數、程序、子空間都會被一起刪除。一般的情況下應該很少用到這個命令才對。
除了上面介紹的操作之外,Tcl還有提供數個名稱空間的功能,有興趣的朋友可以自己去看Tcl的參考手冊。
按右上方的「#」號切換側邊欄