2011-09-23 85 views
3

這種情況下(簡化爲,它並沒有多大意義的點)是由F#正確處理「:爲什麼F#泛型類型推斷在構造函數上有所不同?

type HumanBeing() = class end 
type Animal() = class end 

type CreatureController() = 
    member this.Register creature = creature 

type CreatureFactory() = 
    let anAnimal = new Animal() 
    let aHuman = new HumanBeing() 

    member this.GiveMeAnAnimal = 
     (new CreatureController()).Register anAnimal 

    member this.GiveMeAHuman = 
     (new CreatureController()).Register aHuman 

類型CreatureController.Register的正確推斷出:S型系統」一 - >「一,因此可以用兩個不同的參數來調用它。

現在下面的版本有一點區別:不是將生物作爲參數傳遞給CreatureController.Register,而是傳遞給它的構造函數。

type HumanBeing() = class end 
type Animal() = class end 

type CreatureController(creature) = 
    member this.Register = creature 

type CreatureFactory() = 
    let anAnimal = new Animal() 
    let aHuman = new HumanBeing() 

    member this.GiveMeAnAnimal = 
     (new CreatureController(anAnimal)).Register 

    member this.GiveMeAHuman = 
     (new CreatureController(aHuman)).Register 

第二個例子不能編譯,因爲註冊推斷動物,所以你不能調用new CreatureController(aHuman)

(注:在這種情況下,簡化工廠顯然是有缺陷的,因爲它總是返回相同的動物/ humanBeing,但如果你更換anAnimal/aHuman與功能的這種行爲不會改變)

爲什麼不CreatureControlled在第二種情況下創建爲通用?這是編譯器限制嗎?我錯過了一些非常基本的東西(還在學習......)?

+2

我認爲總結是 - 你不能有一個構造函數本身是泛型的(但是泛型方法是完全正確的)。泛型構造函數意味着整個類型是泛型的,並且必須明確聲明。 –

+0

從答案中可以看出,類型推斷有時可能會讓人頭疼,但我仍然傾向於使用類型註釋來使事情更加清晰。在你的情況下,如果你已經在控制器的構造函數中加入了類型註釋,這會幫助你找到問題 – Ankur

+0

@Tomas你的句子總結得非常好。 –

回答

3

在第一種情況下,如您所述,Register被推斷爲通用的,因此它的工作原理。在第二種情況下,您將兩種不同類型傳遞給非泛型類的構造函數。在這種情況下,必須推斷具體類型。如果添加類型參數傳遞給生物控制器,它的工作原理:

type HumanBeing() = class end 
type Animal() = class end 

type CreatureController<'T>(creature:'T) = 
    member this.Register = creature 

type CreatureFactory() = 
    let anAnimal = new Animal() 
    let aHuman = new HumanBeing() 

    member this.GiveMeAnAnimal = 
     (new CreatureController<_>(anAnimal)).Register 

    member this.GiveMeAHuman = 
     (new CreatureController<_>(aHuman)).Register 

不同的是類型參數必須在類型明確的,但不是功能。另外,構造函數只能處理由類型本身聲明的類型參數。

3

在構造函數的情況下,您可能(或至少含糊不清)您的類型本身是通用的,例如,

type CreatureController<'T>(creature:'T) = ... 

並且在F#中,類型定義的泛型參數必須始終明確指定。

+0

對不起,我必須選擇一個答案,但也要感謝這幫助! –