## 回避 C 指針是要付出代價的
在 C 語言中,在執行這些基本原則時,指針是最簡單明快的工具,像是著名廚師庖丁手里的刀。在靜態類型語言中,任何企圖回避指針的行為,必然會導致編程語言的語法復雜化或者削弱語言的表達能力。
在 C++ 中為了回避指針,發明了引用——本質上一種被弱化了的指針,結果導致 C++ 初學者經常要問『什么時候用指針,什么時候用引用』這樣的問題。在智能指針未問世之前,STL 提供的泛型容器無法存儲引用,為了避免在容器中存儲對象時發生過多的內存復制,往往需要將指針存到容器中。當某個函數在內部創建了一個比較大的對象時,這個函數想將這個對象傳遞給其他對象時,這時如果不借助指針,那只能是將這個大對象作為返回值,然后引發了對象數據不止一次被復制的過程。如果在函數中?`new`?一個大對象,然后以指針的形式將其返回,這又與 C++ 一直想向用戶掩蓋指針的理想發生了矛盾……為了解決這個問題,終于在 C++ 11 里搞出來一個挺復雜挺扭曲的右值引用的辦法,解決了在類的復制構造函數中偷偷的使用指針,但是類的用戶卻看不到指針這樣的問題……
Java 回避指針的策略比 C++ 要高明一些。在 Java 中,即沒有指針也沒有引用。只要是類的實例(對象),無論是將其作為參數傳遞給函數,還是作為函數的返回值,還是將其復制給同類的其他對象,都是在傳地址,而不是在傳值。也就是說,Java 將所有的類實例都潛在的作為指針來用的,只有那些基本類型才是作為值來傳遞的。這種對數據類型進行了明確的區分的態度是值得點贊的,但是當 Java 想將一個函數(方法)傳遞給另一個函數(方法)時,代碼就出現了扭曲,完全不能做到像 C 語言以指針的形式傳遞函數那樣簡潔直觀。
C# 在指針的處理上似乎要比 C++ 與 Java 好得多,但是將那些使用指針的代碼標定為?`unsafe`,這是一種歧視。類似于『嗟,來食!』。廉者不受嗟來之食。
在動態類型語言中,例如 Python,據說是一切皆引用,這樣很好。也可以直接將一個函數作為參數傳遞給另一個函數,甚至還能在一個函數中返回一個函數,這樣更好。動態類型語言在語法、抽象能力、類型安全以及資源管理方面很大程度上超越了 C、C++、Java 這些靜態類型語言,但是用前者編寫的程序的計算速度卻往往比后者慢上一倍。
沒有完美的指針,也不會有完美的編程語言,這一切皆因我們是在機器上編程,而不是在我們的大腦里編程。