<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                附錄: 包(packages) 包(packages),是 Common Lisp 把代碼組織成模塊的方式。早期的 Lisp 方言有一張符號表,即`oblist`【注1】。在這張表里列出了系統中所有已經讀取到的符號。借助 oblist 里的符號表項,系統得以存取數據,諸如對象的值,以及屬性列表等。保存在 oblist 里的符號被稱為 interned。 新一些的 Lisp 方言把?`oblist`?的概念放到了一個個包里面。現在,符號不僅僅是被?`intern`?了,而是被?`intern`?在某個包里。包之所以支持模塊化是因為在一個包里的?`intern`?的符號只有在其被顯式聲明為能被其它包訪問的時候,它才能為外部訪問(除非用一些歪門邪道的招數)。 包是一種 Lisp 對象。當前包常常被保存在一個名為?`\*package\*`?的全局變量里面。當 Common Lisp 啟動時,當前包就是用戶包:或者叫 user (**CLTL1**?實現),或者叫?`common-lisp-user`?(**CLTL2**實現)。 包一般用自己的名字相互區別,而這些名字采用的是字符串的形式。要知道當前包的包名,可以試試: ~~~ > (package-name *package*) "COMMON-LISP-USER" ~~~ 通常,當讀入一個符號時,它就被?`intern`?到當前的包里了。要弄清給定符號所?`intern`?的是哪個包,我們可以 用?`symbol-package`?: ~~~ > (symbol-package 'foo) #<Package "COMMON-LISP-USER" 4CD15E> ~~~ 這個返回值是實際的包對象。為便于將來使用,我們給?`foo`?賦一個值: ~~~ > (setq foo 99) 99 ~~~ 使用?`in-package`?,我們就可以切換到另一個新的包,若有需要的話這個包會被創建出來【注2】: ~~~ > (in-package 'mine :use 'common-lisp) #<Package "MINE" 63390E> ~~~ 此時此刻應該會響起詭異的背景音樂,因為我們已經身處另一個世界:在這里?`foo`?已經不似從前了: ~~~ MINE> foo >>Error: FOO has no global value. ~~~ 為什么會這樣?因為之前被我們設置成?`99`?的那個?`foo`?和現在?`mine`?里面的這個 foo 是兩碼事。【注3】要從用戶包之外引用原來的這個?`foo`?,我們必須把包名和兩個冒號作為它的前綴: ~~~ MINE> common-lisp-user::foo 99 ~~~ 因此,具有相同打印名稱的不同符號得以在不同包中共存。這樣就可以在名為?`common-lisp-user`?的包里有一個?`foo`?,同時在?`mine`?包里也有一個?`foo`?,并且它們兩個是不一樣的符號。實際上,這就是?`package`?的一部分用意所在,即:你在為你的函數和變量取名字的同時,就不用擔心別人會把一樣的名字用在其它東西上。現在,就算有重名的情況,重名的符號之間也是互不相干的。 與此同時,包也提供了一種信息隱藏的手段。對程序來說,它必須使用名字來引用不同的函數和變量。如果你不讓一個名字在你的包之外可見的話,那么另一個包中的代碼就無法使用或者修改這個名字所引用的對象。 在寫程序的時候,把包的名字帶上兩個冒號做為前綴并不是個好習慣。你要是這樣做的話,就違背了模塊化設計的初衷,而這正是包機制的本意。如果你不得不使用雙冒號來引用一個符號,這應該就是有人根本就不希望你引用它。 一般來說,你只應該引用那些被 export 了的符號。把符號從它所屬的包 export 出來,我們就能讓這個符號對其它包變得可見。要導出一個符號,我們可以調用(你肯定已經猜到了) export : ~~~ MINE> (in-package 'common-lisp-user) #<Package "COMMON-LISP-USER" 4CD15E> > (export 'bar) T > (setq bar 5) 5 ~~~ 現在,如果回到了?`mine`?包,那么就可以用一個冒號引用?`bar`?,因為這個名字是外部可見的: ~~~ > (in-package 'mine) #<Package "MINE" 63390E> MINE> common-lisp-user:bar 5 ~~~ 如果把?`bar`?`import`?到?`mine`?里面,我們就能更進一步,讓?`mine`?能和?`user`?包共享?`bar`?這個符號: ~~~ MINE> (import 'common-lisp-user:bar) T MINE> bar 5 ~~~ 在導入?`bar`?之后,我們可以根本不用加任何包的限定符,就能引用它了。現在,這兩個包共享了同一個符號 -- 再沒有一個獨立的?`mine:bar`?了。 萬一已經有了一個會怎么樣呢?在這種情況下,`import`?調用會導致一個錯誤,就像下面我們試著`import`?`foo`?時造成的錯誤一樣: ~~~ MINE> (import 'common-lisp-user::foo) >>Error: FOO is already present in MINE. ~~~ 之前,我們在?`mine`?里對?`foo`?進行了一次不成功的求值,這次求值順帶著使得一個名為 foo 的符號被加入了?`mine`?。由于這個符號在全局范圍內還沒有值,因此產生了一個錯誤,但是輸入符號名字的直接后果就是使它被 intern 進了這個包。所以,當我們現在想把?`foo`?引進?`mine`?的時候,`mine`里面已經有一個相同名字的符號了。 通過讓一個包使用 (use) 另一個包,我們也能批量的引入符號: ~~~ MINE> (use-package 'common-lisp-user) T ~~~ 這樣,所有?`user`?`package`?引出的符號就會自動地被引進到?`mine`?里面去了。(要是?`user``package`?已經引出了?`foo`?的話,這個函數調用也會出一個錯。) 根據 CLTL2,包含內建操作符和變量名字的包被稱為?`common-lisp`?而不是?`lisp`?,因此新一些的包在缺省情況下已不再使用?`lisp`?包了。由于我們通過調用`in-package`?創建了?`mine`?,而在這次調用中也?`use`?了這個包,所以所有?`Common Lisp`?的名字在?`mine`?中都是可見的: ~~~ MINE> #'cons #<Compiled-Function CONS 462A3E> ~~~ 在實際的編程中,你不得不讓所有新編寫的包使用 common-lisp (或者其他某個含 Lisp 操作符的包)。否則你甚至會沒辦法跳出這個新的包。【注4】 一般來說,在編譯后的代碼中,不會像剛才這樣在頂層進行包的操作。更多的時候,這些關于包的函數調用會被包含在源文件中。通常,只要把 in-package 和 defpackage 放在源文件的開頭就可以了。 (defpackage 宏是?**CLTL2**?里新引進的,但是有些較老的實現也提供了它。) 如果你要編寫一個獨立的包,下面列出了你可能會放在對應的源文件最開始地方的代碼: ~~~ (in-package 'my-application :use 'common-lisp) (defpackage my-application (:use common-lisp my-utilities) (:nicknames app) (:export win lose draw)) ~~~ 這會使得該文件里所有的代碼,或者更準確地說,文件里所有的名字,都納入了?`my-application`?這個包。 `my-application`?同時使用了?`common-lisp`?和?`my-utilities`?,因此,不用加任何包名作為前綴,所有被引出的符號都可以直接使用。 `my-application`?本身僅僅引出了三個符號,它們分別是:`win`、`lose`?和?`draw`?。由于在調用`in-package`?的時候,我們給?`my-application`?取了一個綽號?`app`?,在其它包里面的代碼可以用類似?`app:win`?的名字來引用這些符號。 像這樣的用包來提供的模塊化的確有點不自然。我們的包里面不是對象,而是一堆名字。每個使用`common-lisp`?的包都引入了?`cons`?這個名字,原因在于?`common-lisp`?包含了一個叫這個名字的函數。但是,這樣會導致一個名字叫?`cons`?的變量也在每個使用?`common-lisp`?的程序里可見。這樣的事情同樣也會在?`Common Lisp`?的其他名字空間重演。如果包(package) 這個機制讓你頭痛,那么這就是一個最主要的原因 -- 包不是基于對象而是基于名字。 和包相關的操作會發生在讀取時(read-time),而非運行時。這可能會造成一些困擾。我們輸入的第二個表達式: ~~~ (symbol-package 'foo) ~~~ 之所以會返回它返回的那個值是因為:讀取這個查詢語句的同時,答案就被生成了。為了求值這個表達式,`Lisp`?必須先讀入它,這意味著要?`intern`?`foo`。 再來個例子,看看下面把兩個表達式交換順序的結果,這兩個表達式前面曾出現過: ~~~ MINE> (in-package 'common-lisp-user) #<Package "COMMON-LISP-USER" 4CD15E> > (export 'bar) ~~~ 通常來說,在頂層輸入兩個表達式的效果等價于把這兩個表達式放在一個progn 里面。不過這次有些不同。如果我們這樣說 ~~~ MINE> (progn (in-package 'common-lisp-user) (export 'bar)) >>Error: MINE::BAR is not accessible in COMMON-LISP-USER. ~~~ 則會得到個錯誤提示。錯誤的原因在于?`progn`?表達式在求值之前就已經被 read 處理過了。當調用 read 時,當前包還是 mine ,因而 bar 被認為是 mine:bar 。運行這個表達式的效果就好像我們想要從 user 包 export 出 mine:bar ,而不是從?`common-lisp-user`?export 出?`common-lisp-user:bar`?一樣。 `package`?被如此定義,使得編寫那些把符號當作數據的程序成為一樁麻煩事。舉個例子,要是像下面那樣定義 noise : ~~~ (in-package 'other :use 'common-lisp) (defpackage other (:use common-lisp) (:export noise)) (defun noise (animal) (case animal (dog 'woof) (cat 'meow) (pig 'oink))) ~~~ 這樣的話,如果我們從另外一個包調用 noise ,同時傳進去的參數是不認識的符號,noise 會走到 case 語句的末尾,并返回 nil : ~~~ OTHER> (in-package 'common-lisp-user) #<Package "COMMON-LISP-USER" 4CD15E> > (other:noise 'pig) NIL ~~~ 這是因為傳進去的參數是?`common-lisp-user:pig`?(這沒有冒犯閣下的意思),然而?`case`?接受?`key`是?`other:pig`?。為了讓?`noise`?像我們期望的那樣工作,就必須把里面用到的所有六個符號都引出來,再在調用 noise 的包里面引入它們。 在此例中,我們也可以通過使用關鍵字而不是常規的符號,來繞過這個問題。倘若 noise 像下面這樣定義: ~~~ (defun noise (animal) (case animal (:dog :woof) (:cat :meow) (:pig :oink))) ~~~ 的話,我們就能從任意一個包安全地調用這個函數了: ~~~ OTHER> (in-package 'common-lisp-user) #<Package "COMMON-LISP-USER" 4CD15E> > (other:noise :pig) :OINK ~~~ 關鍵字就像金子:普適而且自身就能表明其價值。不論在哪里它們都是可見的,而且它們從不需要被引用。 在編寫類似?`defanaph`?( 16.3 節) 的符號驅動的函數時,基本上應該總是用關鍵字參數。 包里面有很多地方讓人不解。這里對這一主題的介紹不過是冰山一角。要知道所有的細節,請參考**CLTL2**?的第 11 章。 備注: 【注1】譯者注:GNU Emacs 和 XEmacs 使用的是一張名為 obarray 的哈希表。 【注2】在較早期的 Common Lisp 實現下,請省略掉 :use 參數 【注3】有的 Common Lisp 實現會在 toplevel 提示符的前面顯示包的名字。這個特性不是必須的,但的確是比較貼心的設計。 【注4】譯者注:即你不僅沒有辦法使用cons ,更糟糕的是,你也不能用in-package 切換到其它包。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看