■ 對象
F#的面向對象是與.NetFramework的面向對象有着緊密聯繫的。也就是說,F#具備了與C#等.NetFramework中的語言中面向對象所相同的面向對象機制。因此,F#中支持了OCaml中所不支持的重載(overload)功能,但是另一方面,作爲其結果,OCaml中所具有的類型推理的完全性在F#中就不具備了。另外,關於類的描述方法也與Ocaml不同,所以論及面向對象這一部分,F#是與Ocaml互不兼容的,最好理解成兩種不同的語言比較好。(關於重載在後文詳述)。
類型推理的完全性是指 |
那麼,讓我們來開始針對面向對象進行思考。
首先,如果可以針對面向對象作個精確定義就好了,但是面向對象並不是這麼簡單的。
因爲,構成面向對象這種想法的起源並不是單一的一門語言,是由多個語言共同構成的,而各個語言中關於面向對象的想法又各有區別。
例如,大多數面向對象的語言中,類是一種模式,實現類並創建對象叫做實例化。
因此,將對象與類分開來考慮的語言有很多,但是在面向對象的起源之一的Smalltalk等語言中,類本身就是對象,綜合起來,就很難對面向對象進行定義了。
首先,關於類,它是將數據與函數進行集中彙總之後產生的。但是在各個語言中對於數據和函數的稱呼方法又各不相同。例如在Java中,將數據稱爲字段,函數稱爲方法,在C++中將數據稱爲成員變量,函數稱爲成員函數。本書結合Expert F#或Foundations F#的稱呼方法,在有必要作區分時,將數據稱爲字段,函數稱爲方法或成員函數,沒必要進行區分時統稱爲成員。
類具有繼承的概念,繼承了某個類後的類也繼承了被繼承類中的所有成員。本書中將被繼承的類稱爲父類,繼承父類的類稱爲子類。
接着讓我們進入正題。在.Net Framework中面向對象的代表性語言爲C#。一切都是object類的子類。也就是說,所有的類型都可上溯(Upercast)爲Object類型。F#中也有相當於這種Object類型的obj類型,所有的類型都可上溯爲obj類型。
let a = 1 :> obj;; |
:>是上溯時使用的運算符。上溯是指,將任何對象的類型轉變爲該對象父類的類型,反之將任何對象的類型轉變爲該對象子類的類型稱之爲下溯。上溯是安全的,因爲編譯器總是知道該對象的父類型,下溯是不安全的,因爲當前類型未必能夠轉化爲目標子類型。
在F#中把各類型之間的轉變稱爲轉換。轉換成obj類型是把任意類型轉變成obj類型,與box函數作用相同。
> let a = box 1;; |
同時,也具有unbox函數用來把obj類型的函數轉變成原有類型。但是,如果轉換不成功則會引發異常,請注意這一點。
> let a = box 1;; |
因此,下溯時通常使用類型測試運算符:?來判斷是否能實現轉換。
let a = box 1 in |
類型測試運算符可以當作函數那樣來利用。如果象( obj :? type )這樣來使用時,obj可以轉換爲type時返回true,否則返回false。
> let a = box 1 in if (a :? int) then true else false;; |