2011-09-23 87 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

对不起,我必须选择一个答案,但也要感谢这帮助! –