多語言模式並舉.NET 語言和模式的調查

 
多語言模式並舉
.NET 語言和模式的調查
Joel Pobar
本文討論:
  • 面向對象的編程
  • 函數式編程
  • 動態編程
  • .NET 語言的新模式
本文使用了以下技術:
C#、C++、F#、IronPython、IronRuby、Visual Basic

 

 

Windows 操作系統 對編程人員而言是再合適不過的平臺了。針對 Windows® 的語言有數百種,它們有的直接通過 Win32® API 或 CLR 來實現,但更多的還是通過您的編寫來構建。
CLR 的目標之一就是要在一個兼容的生態系統中讓百花齊放,將語言和 API 無縫集成在同一運行時中。到目前爲止它已取得了巨大的成功——新的語言層出不窮。像 Ruby (IronRuby)、Python (IronPython) 和 PHP (Phalanger) 等 Microsoft 實現屬於動態語言範疇,它們現在是 Microsoft® .NET Framework 語言中的一流成員。最近還引入了被稱爲 F# 的函數化語言。儘管您很可能曾經聽到過有關這些新語言和語言模式的討論,但可能還是想知道其具體含義。
介紹這些語言模式並講述其中一些重要實現的內容不但能夠解答您的疑問,而且還有助於說明其中的一些新語言和舊模式將會如何影響 C# 和 Visual Basic® 語言未來版本的設計和實現。
要了解新設計所表現出來的變化,您需要了解傳統語言(如 C# 和 Visual Basic)與新語言(如 F#、IronPython 和 IronRuby)之間的差異。此方面主要涉及三大主題:面向對象的編程(C# 和 Visual Basic 這二者都利用的模型)、函數式編程 (F#) 以及動態編程(IronPython 和 IronRuby)。讓我們看一看這些模式並探究一下他們的區別特徵。

 

面向對象

面向對象
面向對象 (OO) 是您可能最爲熟悉的一種模式。通過它您可以描述對象與綁定它們之間交互的約定所構成的環境。OO 利用類型約定、多態性以及精細的可見性等多種功能來提供出色的重用和封裝特性。
通常,面向對象的語言採用靜態類型系統,因此它們被稱爲靜態類型語言。這意味着程序創建和使用的所有類型都在編譯時進行檢查;這可防止您對 Duck 類型的對象調用方法 Moo(在此方法不存在的情況下)。在代碼運行之前,編譯器可檢測各種類型之間被破壞和誤用的約定,從理論上講,這樣做可減少運行時錯誤。
但是 OO 也存在一些缺陷。類型安全性可能會使編程人員過分依賴編譯器來捕獲錯誤,而不是親自創建必要的測試基礎結構。同時,OO 還會促使編程人員預先定義自己的約定,而這往往是與快速原型編程和多用戶編程環境背道而馳的。在大型軟件項目中,組件之間的約定(通常由不同的團隊所擁有)往往在整個開發週期中不斷演變,這就要求約定的使用者不斷更新其代碼。由於上述這些問題,OO 語言可能顯得有些複雜和冗長。

 

函數式編程
函數式編程將程序計算視爲數學函數的計算。將兩個數字相加即爲一個函數。假定有兩個輸入值,比方說是 5 和 10,則輸出值便爲 15。爲解決某個問題,函數式編程人員會將該問題細分爲多個可使用函數表示的較小的塊,然後再將這些函數進行組合以生成預期的輸出。
函數式編程通常會避開狀態(類似於變量和對象等內容)和狀態變異。這實際上是與 OO 相左的,後者的主要目的恰恰是爲了創建和操作狀態(對象)。由於避開了狀態,函數式程序往往更加準確、精密而且可驗證。這是由於它很少會產生不可預知的副作用——當程序(如某個變量)的內部狀態在各操作之間發生變化時可能會產生一些副作用,這些副作用會導致在一個或多個操作中產生非預期的結果。面向對象的語言和動態語言依賴編程人員來封裝和保護狀態,以減少不可預知的副作用,因爲這些副作用會不可避免地導致更多錯誤的發生。
函數式語言可以是很純粹的,也就是說沒有任何副作用或狀態。但是,大多數流行的函數式語言都具有狀態操作功能,這有利於促進與外部 API、操作系統以及其他語言的互操作性。針對某些程序必須使用一定量的狀態信息來表示問題這一事實,它們也有相應的考慮。
有一些很有用的功能,它們對函數式語言是通用的。就我個人而言,我比較喜歡高階函數,此函數可以將另一個函數作爲參數,並且返回結果可以是函數,這爲代碼重用提供了強大的支持。雖然大多數語言已嵌入了此機制,但函數式語言更傾向於將其提升爲首要的功能。
下面將以一個典型的 Map API 爲例來詳細介紹高階函數的功能,此示例對數組或數據列表中的每個元素都執行(或映射)一個函數。首先,我們使用 JavaScript(一種常用的 Web 腳本編寫語言)來編寫此函數。給定此數組
var data = [1, 2, 3, 4, 5];
現在編寫將對數組中的每個元素執行代碼的函數,如下所示:
function map (func, array)
{
    var returnData = new Array(array.length);
    for (i = 0; i< array.length; i++)
    {
        returnData[i] = func(array[i]);
    }
        
    return returnData;        
}
下面的函數將按 1 遞增某個數值:
function increment(element)
{
    return element++;
}
現在讓我們開始使用它:
print (map (incremenent, data));

output: [2,3,4,5,6]
此處的 Map API 示例雖然非常簡單,但卻演示了高階函數的功能。Map 有一個函數和一個數組,它對每個數組元素都執行該函數,並在一個新數組中返回結果。
假定沒有變異的狀態(爲返回的結果創建一個新數組),並且沒有函數結果依賴於先前的結果,則現在即可開始考慮將這一映射示例擴展到多個處理內核(通過將數組分成兩部分並將得到的兩個數組連接起來)乃至多個計算機(跨 n 個計算機拆分序列化數據、將代碼函數傳遞到計算機、在一個單獨主機中執行並連接序列化結果),而不必擔心諸如狀態管理等併發操作問題。如此強大的功能用在這裏真的是大材小用了!
編程語言 F# 最初是由 Microsoft Research 的 Don Syme 所開發,是 Microsoft 對有關 .NET Framework 函數化編程需求的迴應。在發佈時,它將是在 Visual Studio® 中受到全面支持的語言。F# 和 Visual Studio 集成包均可從 go.microsoft.com/fwlink/?LinkId=112376 下載。另外,由 Robert Pickering 編寫的 Foundations of F# 對該語言做了精彩的介紹。
言歸正傳,下面我們將使用 F# 來探究函數化語言環境的內幕。我們仍以 Map 爲例,但這次是在 F# 中:
// increment function
let increment x = x + 1

// data
let data = [1 .. 5]

// map (func, myList)
let map func myList = 
  { for x in myList -> func x }

print_any (map increment data)
的確,它非常簡潔。第一行定義一個簡單的遞增函數,它有一個參數 x,此函數將計算 x + 1。然後,將數據定義爲一個不可變異的列表,其中包含整數 1 到 5。此映射函數以函數和列表作爲參數,使用傳統編程中的噴淋方法來遍歷列表並執行 func 函數參數,然後將列表中的當前元素傳遞給它。接下來,print_any 函數使用增量函數和數據列表作爲參數來執行映射函數,隨後將結果打印到屏幕。
類型在哪裏?在本例中並不存在。實質上,變量(數據)實際被類型化爲 System.Int32 的列表,但並不需要將此告知編譯器,因爲它使用類型推斷功能即可推斷出這一情況。編譯器做的工作越多,您的工作就會越少。這聽起來非常不錯。使用列表推導功能,您在一行內就可以輕鬆地重寫先前的部分代碼:
print_any { for x in 1..5 -> x + 1 }
另一個很酷的 F# 功能是模式匹配:
let booleanToString x = 
   match x with false -> "False" | _ -> "True"
此函數具有一個 Boolean 類型,此類型可與 false 或任何其他值匹配,並返回相應的字符串。如果向 booleanToString 函數傳遞一個字符串,會出現什麼結果?同樣,編譯器承擔了繁重的工作,將 x 參數的類型定義爲類型 bool。它通過 x 在此函數中的用法推斷出這一點(在這種情況下,它僅與 bool 類型相匹配)。
模式匹配還可以用於構建強大的函數調度機制,以便在 OO 及其他環境中輕鬆地重現虛擬方法調度。當您需要根據接收方(將在此對象中調用虛擬方法)和方法參數的變化來改變行爲時,虛擬方法才真正開始起作用。訪問者模式即是爲了幫助解決這種情況而設計的,但是在 F# 中基本不需要(已包含在模式匹配中)。
支持用戶定義的類型,通常由記錄(類似於 OO 環境中的類)或聚合(通常是一種有序序列類型)提供。以下是用戶定義的隊員和球隊記錄:
type player = 
  { firstName : string; 
    lastName : string;
  }

type soccerTeam = 
  { name : string;
    members : player list;
    location : string;
  }  
延遲計算是另一種常見的函數式語言功能,其功能源自這樣一種理論,即函數化編程中沒有明顯的副作用。延遲計算依賴於編譯器和編程人員選擇表達式計算順序的能力,它可以使計算延遲到所需的時間點。編譯器和編程人員都可以使用延遲計算技術作爲精確的性能優化手段,因爲它可以避免一些不必要的計算。在處理無限(或極大)數據集的計算時,它也是一種有用的技術。實際上,Microsoft Research 的 Applied Games 研究組曾在 F# 中使用此技術解析過數 TB 字節的 Xbox LIVE® 日誌數據。
以下是 F# 中的延遲計算:
	let lazyTwoTimesTwo = lazy (2 * 2)
 
	let actualValue = Lazy.force lazyTwoTimesTwo
此代碼執行時,lazyTwoTimesTwo 只是在運行時充當指向執行 2 * 2 的函數的輕型指針。僅當實際強制執行此函數時,才能獲得結果。
雖然函數化編程模型可能不太容易理解(可能需要 30-40 小時的準備時間),但一旦掌握它,您的編程能力就會有質的飛躍。您只需使用很少的代碼就可以解決問題並減少錯誤。此模式通過最大程度減少意外的副作用來保護代碼的安全,並通過執行積極的優化措施使其保持快速運行狀態。此外,簡單性往往代表出色的擴展性——您只需看一下 Map 代碼,想想該代碼如何能夠輕鬆分佈到成千上萬臺計算機中,就可以瞭解其中的緣由了。
至此,您已經看到了函數化編程的一些非常出色的功能,例如類型推斷、高階函數、模式匹配和用戶定義類型等。現在讓我們瞭解一下動態語言。

 

動態語言
動態編程早在 20 世紀 90 年代中期就開始流行了,當時正是基於 Web 的應用程序大行其道的時候。在將服務器上的交互式動態元素添加到它們所驅動的網站上時,Perl 和 PHP 是最常用的兩種動態語言。從那以後,動態語言開始獲得越來越多的驅動力,爲新一代軟件開發方法(如敏捷開發)指明瞭技術出路。
在編譯和執行程序代碼方面,動態編程語言與靜態語言(C# 和 Visual Basic .NET 均爲面向對象的靜態語言)有所不同。使用動態語言時,代碼編譯通常會被延遲到運行時,即當實際開始運行程序的時候。在其他情況下,只是簡單地對代碼進行解釋。通過編譯過程中的這些延遲功能,程序代碼可以包括並執行諸如動態擴展對象等行爲,並允許編程人員根據需要來處理類型系統。
實際上,正是將進程延遲到最後一刻的實時 (JIT) 編譯和執行技術爲動態語言賦予了強大而又豐富的功能集。因此,動態語言通常被稱爲後期綁定,因爲所有操作綁定(如調用方法或獲取屬性)都是在運行時而非編譯時完成的。爲了說明動態語言的一些功能,下面我們將詳細介紹一下 IronPython 和 IronRuby。
IronPython 是 .NET Framework 中 Python 編程語言的 Microsoft 實現。它是 Jim Hugunin 智慧的結晶,其原型最早是誕生在 Jim Hugunin 的車庫中。六個月後,Jim Hugunin 加入了 Microsoft 並構建了 IronPython 編譯器。您可以從 go.microsoft.com/fwlink/?LinkId=112377 下載 IronPython 的完整源代碼和安裝程序。
IronRuby 是爲 Ruby 編程語言的 Microsoft 實現所賦予的名稱。John Lam 是一名活躍的 Ruby 黑客,他編寫了名爲 RubyCLR 的 Ruby-to-CLR 橋樑。後來他加入了 Microsoft 的 IronRuby 團隊。您可以從 ironruby.net 下載完整的 IronRuby 源代碼。
接下來,我們將開始使用 IronPython,介紹一項名爲 Read Eval Print Loop (REPL) 的出色功能。REPL 循環被設計用於逐行輸入代碼並執行。它實際展示的是動態語言(如 Python)的後期綁定性質。圖 1 顯示了 IronPython 的命令行 REPL 循環。
圖 1 IronPython REPL 循環 (單擊該圖像獲得較大視圖)
REPL 循環接受 Python 代碼作爲輸入,然後它將立即執行代碼。在本例中,我想讓它將 "Hello, World!" 打印到屏幕上。只要編程人員敲擊一下 Enter 鍵,IronPython 編譯器就會將該語句編譯爲中間語言 (IL) 並執行(全部都在運行時中)。
REPL 循環還遵循該語言的全部作用域規則,在本例中,我將表達式 1 + 2 賦給了變量 "a",在下一行中我將可以引用此變量。REPL 輸入內容的編譯是在進程內進行的。無需生成 .dll 或 exe 文件;IronPython 編譯器僅使用 CLR 的內存代碼生成功能,即輕量級代碼生成 (LCG)。
動態語言的類型系統非常靈活,而且要求寬鬆。通常它可以支持面向對象的概念(如類和接口),不過需要注意:在靜態語言中存在的嚴格的約定強制執行情況在這裏一般不會出現。對於這一相對較爲寬鬆的類型系統,一個典型示例就是鴨子的類型化概念,這是一種受到廣泛支持的動態語言類型系統功能。在鴨子類型化中,如果某個類型看上去像鴨子並且叫起來也像鴨子,則編譯器就會假定它是鴨子。圖 2 使用 Ruby 顯示了運行中的這一概念,如果願意,您也可以在 IronRuby 中運行此代碼。

 

 

圖 2 顯示了兩個類定義(Duck 和 Cow)、一個名爲 QuackQuack 的方法以及用來實例化這些對象的代碼,然後又將對象傳遞給 QuackQuack 方法。此代碼在加載並運行後會輸出以下內容:
Quack!
Cow's don't quack, they Mooo!
QuackQuack 方法通過方法參數調用 Quack 方法,它並不關心該參數的類型,只關心該參數是否有方法 Quack。Quack 方法的查找和調用是在此參數的運行時而非編譯時進行的,這將允許編程語言先確保該參數看上去形似鴨子,然後再考慮其叫聲。
在靜態類型化環境中,接口就類似於上面所說的鴨子類型化。如果某個類型要在靜態環境中實現某個接口,則靜態類型系統會強制其遵循全部完整的接口結構,以使對任何實現類型的接口方法調用都能夠得到保證。鴨子類型化僅關注類型的結構部分,即所處理的方法名稱。它通過後期綁定來實現該目的——編譯器只生成代碼,對對象執行方法查找(通常使用基於字符串的方法名稱),然後再調用該方法(如果查找成功)。
在 IronPython 和 IronRuby 等動態語言中,語言功能並非是唯一的亮點。動態語言甚至還允許您託管 API,這意味着您可以在自己的應用程序中託管語言、編譯器甚至 REPL 交互式功能。假設您正在構建一個龐大而複雜的應用程序(例如照片處理工具),而且您希望爲用戶提供一個自動化或腳本處理工具。您可以託管 IronPython 或 IronRuby 並允許用戶創建 Python 或 Ruby 腳本,使其可以通過編程方式來操作您的應用程序。爲此您只需將應用程序的內部對象和 API 提供給託管 API 的語言、創建一個文本窗口來託管 REPL 循環、然後在應用程序中啓用腳本編寫功能即可。
使用諸如命令行驅動 REPL 循環等功能可以在生產力方面帶來非常不錯的連帶效應:您可以輕鬆地構造工作原型而不必執行保存-編譯-運行這一週期。我們提倡動態修改和擴展類型,這可以使您快速獲得解決方案(從構想到代碼),而無需擔心接口或類定義約定的形式。取得進展後,您即可從動態語言原型轉到更嚴格、更安全的靜態語言環境(如 C#)中。
實際上,靈活的類型系統還擅長處理非結構化的數據(如 Web 上的 HTML),對於可能會隨着時間的推移而更改版本的嚴格接口而言,可以很容易地將其用作防更改粘合劑。在基於 Web 的計算等新興應用程序模式中,動態語言提供了一種用於處理不確定情形的強大解決方案。
託管 API 會爲您的應用程序提供一個最佳的擴展點;您可以提供與 Microsoft Excel® 和 VBScript 宏類似的應用程序體驗。

 

安全實用
安全性和實用性也是在語言選擇中需要考慮的重要事項。語言的實用性可通過其易用性、高效性等因素來衡量。語言安全性的衡量標準包括其類型安全性(是否允許無效轉換)、編程屏障(是否會跨越數組邊界並影響堆棧中的其他內存內容)、安全功能等等。有時您可以犧牲實用性來換取安全性,反之亦然。
有趣的是,您會發現 C#、C++、Visual Basic .NET、Python 及類似的語言實用性很強,但缺少安全分類。雖然託管代碼語言(如 C#)要比傳統的本機代碼安全一些,但您仍可能會遇到麻煩。由於這些語言關注的是狀態操作,因此它們通常都有一些未知的副作用——在併發環境下工作時,這將會是一個問題。
在單核計算機中可以正常運行的一個 C#/Visual Basic .NET 多線程程序,在多核計算機中運行時可能會崩潰,這是由於爭用條件引發了一個編程人員所不知道的副作用。另外,儘管這些語言具有良好的一般等級的類型安全性,但是它們仍然無法防止編程人員在沒有察覺的情況下將某個對象轉換爲 void*。
Haskell(學術界使用的一種純函數式語言)屬於雖然安全但實用性稍差的一類。由於 Haskell 沒有副作用(代碼塊是函數,變量永遠不會變化),而且它會強制編程人員預先定義其類型和意圖,因此它被視爲一種安全語言。遺憾的是,Haskell 極難理解,甚至對技術精湛的編程人員也是如此,因此通常很難讀懂他人所編寫的 Haskell 代碼。
在我看來,考慮到與 .NET Framework 的集成、可選的過程語法、處理面向對象環境下的 Objects 的能力等特點,因此 F# 要比 Haskell 更爲實用。很顯然,下一代語言會很好地借鑑我所介紹的這些語言的長處。如果有一種語言能夠將呆板、強制性的靜態類型系統動態地變爲動態、靈活的類型系統,不但具有函數化編程功能而且可以避免併發問題,那有誰會不喜歡這種語言呢?
令人欣慰的是,由於通用類型系統 (CTS) 的出現,現在可以很容易地從 C# 轉換到 F# 和 IronPython,然後再重新轉換回來。而且 C# 和 Visual Basic .NET 的設計人員借鑑了動態模式和函數化模式的長處,將其直接集成到了這些語言中作爲優先功能。接下來讓我們瞭解一下其中的幾個功能,看一看它們是如何與您已經瞭解的各種語言及其模式相關聯的。

 

LINQ
LINQ 是 .NET Framework 中的一項新功能,可直接用作 .NET 中任何語言的 API,也可以通過一組 LINQ 語言擴展來實際作爲一種語言功能。通過提供一組與 T-SQL 語言類似的查詢運算符,LINQ 可以使用一種與存儲無關的方式來查詢數據。.NET Framework 3.5 中的 Visual C#® 2008 和 Visual Basic 2008 均支持 LINQ 作爲一流成員。
使用 Visual C# 2008 執行的典型 LINQ 查詢如下所示:
List<Customer> customers = new List<Customer>();
// ... add some customers
var q = from c in customers
        where c.Country == "Australia"
        select c;
此代碼會遍歷客戶列表,查找包含 Country 屬性且屬性值爲 "Australia" 的 Customer 對象,然後將其添加到新列表中。首先您會注意到關鍵字 "var",它是 Visual C# 2008 中新增的一個關鍵字,用來告訴編譯器執行類型推斷。然後您會看到操作中的 C# LINQ 擴展,其中包含 from、where 和 select 關鍵字。這些構成了一個完整的客戶列表(列表推導),正如您在 F# 語言中看到的,這是動態語言中的一個常見功能。
由於您是在此 LINQ 查詢執行時新建列表,因此實際上沒有任何副作用,原始客戶列表不會發生改變。副作用對每個併發程序而言都是一件很麻煩的事,但這種編程風格會在副作用中爲您帶來安全性,同時維護代碼的可讀性和整體實用性。假定沒有任何副作用,則您可根據需要對查詢範圍進行擴展。
實際上,這正是 Parallel LINQ (PLINQ) 的目的所在,它是對 LINQ 的擴展,作爲社區技術預覽通過 Parallel FX 庫 (go.microsoft.com/fwlink/?LinkId=112368) 提供給用戶——跨多個 CPU 核心並行執行 LINQ 查詢,這樣不但使查詢速度幾乎呈線性增加,而且不會增加編程成本!這與函數式編程部分列舉的 Map API 示例非常相似。總之,LINQ 在 C# 和 Visual Basic 中的集成不但增加了一個函數類型,還引入了一些活力,它使這些語言更具表現力,而且更簡練。

 

Visual Basic 9.0 中的內嵌 XML
有人說內嵌 XML 是 Visual Basic 中添加的最佳功能,我完全同意。雖然它不像是源自函數式或動態模式的內容,但它的實現是直接在動態語言環境中完成的。圖 3 顯示了在 Visual Basic 中內嵌的 XML。

 

 

此代碼使用 Visual Basic LINQ to XML 實現來查詢客戶列表中那些居住在美國的客戶,並返回 XML 元素的列表作爲 RSS 源的基礎。然後,此代碼定義 RSS 源架構並使用 Visual Basic 中非常奇妙的 "..." 運算符來遍歷 XML 文檔以查找 "<channel>" 元素。接下來,代碼對該 <channel> 元素調用 ReplaceAll,以包括在先前創建的所有 XML 元素。大功告成。
在這裏需要注意的是 ... 運算符以及內嵌 XML 元素的使用。請注意,Visual Basic 並不知道 XML <channel> 元素(實際上,您可以將其改爲 <foo>,它也會正常編譯),因此說,如果 Visual Basic 不知道這一點,可能就無法靜態檢查該調用點是否正確。相反,在這裏編譯代碼將會在運行時執行動態檢查(類似於您在動態模式下見到的檢查)。它利用的是後期綁定中的動態語言概念。
對於早餐準備享用 IL 的用戶,讓我們打開程序集,看一看 "...<channel>" 語句的代碼:
ldloc.1
ldstr      "channel"
ldstr      ""
call       class [System.Xml.Linq]System.Xml.Linq.XName
     [System.Xml.Linq]System.Xml.Linq.XName::Get(string,
                                             string) 
callvirt   instance class Generic.IEnumerable'1<XElement>
           XContainer::Descendants(System.Xml.Linq.XName)
Ldloc.1 加載 rssFeed 變量、加載 channel 字符串,然後調用 XName.Get 方法,此方法返回 Xname。此 XName 結果被傳遞給 Descendants 方法,然後此方法返回與 <channel> 名稱匹配的所有 XML 文檔後代。此機制是典型的後期綁定動態調度,它直接借用了動態語言的內容。
別急,還有一些內容需要討論。如果將 RSS 架構定義置入 Visual Studio 中並添加對此架構的 "Imports" 引用,則 Visual Basic .NET 編譯器將提取此架構並加以分析,然後對符合此架構的所有 XML 啓用完整的 IntelliSense®。因此,如果您進入 RSS XML 架構中,"...<channel>" 語句會立即顯示一個 IntelliSense 窗口,其中包含根據架構定義提供的各種可能的後代選項。太棒了!

 

更多資源
有關 C# 和 Visual Basic 等語言如何與其他模式和語言的最佳元素相結合的內容,我僅提及了少數幾個示例。現在,語言設計團隊正在向其語言中增加新的類型,以應對未來編程的挑戰。
雖然我們已經探討了幾個高級別的編程模式類別,但這些只是其中的一部分。聲明性編程(描述某種事物的方法)使用 XML 作爲描述符,對通過框架(如 Windows Presentation Foundation 和 Windows Workflow Foundation)進行的開發有着巨大的影響。它們還非常擅長描述和操作數據。隨着組織多年來所創建的數據資產的不斷增長,如果今後想嘗試通過編程方式來開發這些資產,我想聲明性語言會成爲其中的驅動力。還有一種邏輯編程(利用計算機編程邏輯),雖然我沒有提及這種編程方法,但它與 Prolog 等語言一起被廣泛地應用在人工智能和數據挖掘領域。
隨着不斷向所有這些語言和模式中添加各種新功能,您也必將從中獲益。通過這種取長補短,您所喜愛的語言會變得更加完善,而您也可以獲得更大的靈活性和更高的生產率。如果您想使用其他語言中的一些比較出色的功能,這也好辦;您所喜愛的運行時和框架已經開始支持這種互操作情形。作爲一名 .NET 編程人員真是太棒了。

 

Joel Pobar 以前是 Microsoft CLR 團隊的一名項目經理。他現在住在澳大利亞的黃金海岸,潛心鑽研編譯器、語言和其他一些有趣的東西。您可以在 callvirt.net/blog 上查看他的最新 .NET 隨筆。

 

Dim rss = From cust In customers _
          Where cust.Country = "USA" _
          Select <item>
                     <title><%= cust.Name %></title>
                     <link><%= cust.WebSite %></link>
                     <pubDate><%= cust.BirthDate %></pubDate>
                 </item>

Dim rssFeed = <?xml version="1.0" encoding="utf-8"?>
    <rss version="2.0"><channel></channel></rss>

rssFeed...<channel>(0).ReplaceAll(rss)
rssFeed.Save("customers.xml")

 

class Duck
  def Quack()
     puts "Quack!"
  end
end

class Cow
  def Quack()
    puts "Cow's dont quack, they Mooo!"
  end
end

def QuackQuack(duck)
  duck.Quack()
end

animal = Duck.new()
QuackQuack(animal)
animal = Cow.new()
QuackQuack(animal) 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章