我有一个泛型类,默认构造函数接受泛型类型的参数。当创建第二个非泛型构造函数时,F#编译器会抱怨This type parameter has been used in a way that constrains it to always be 'EmptyType'
,我根本不理解这个错误。为什么会受到限制?第二个构造函数与第一个构造函数的泛型属性有什么关系?
此示例显示了错误(在F#操场中可重复(。注意,只需注释第二个构造函数(第9行(,就可以解决编译问题:
type MyInterface = interface end
type EmptyType() = interface MyInterface
type RealType(v: int) =
member this.Value = v
interface MyInterface
type MyType<'T when 'T :> MyInterface>(element: 'T) =
new() = MyType(EmptyType())
member this.X = 0
[<EntryPoint>]
let main _ =
//let a = MyType() //empty constructor, 'T is EmptyType
let b = MyType(RealType(0)) //doesnt work because compiler says 'T is always EmptyType? what?
0
构造函数不能是泛型的。您的类型是泛型的,但每个构造函数都必须返回定义它的确切类型。不能让一个构造函数返回MyType<'t>
,另一个构造函数则返回MyType<EmptyType>
。如果在MyType<'t>
上定义了构造函数,则它必须返回MyType<'t>
,而不能返回MyType<EmptyType>
当编译器看到其中一个构造函数总是返回MyType<EmptyType>
时,它得出结论,类型参数't
必须始终等于EmptyType
。正是在这个意义上,参数't
被约束为EmptyType
,正如错误消息所说。
没有办法让构造函数返回与定义它的类型不同的类型。如果必须专门构造MyType<EmptyType>
的实例,则可以使用静态方法:
type MyType<'t>(t: 't) =
static member CreateEmpty () = MyType(EmptyType())
然而,请注意,要调用这样的方法,您仍然需要为MyType
提供一些类型参数,例如:
let x = MyType<RealType>.CreateEmpty()
或者你可以使用通配符:
let x = MyType<_>.CreateEmpty()
由于没有根据推断通配符应该是什么,编译器将回退到obj
(或最接近的约束(,因此上述调用将等效于MyType<obj>.CreateEmpty()
。还是很尴尬。
为了避免这种情况,一个更好的方法是使用一个同名的模块:
module MyType =
let createEmpty() = MyType(EmptyType)
let x = MyType.createEmpty()
此模式广泛用于泛型类型。例如,请参见Option
或List
。
不确定在这种情况下,对重载构造函数的具体限制是什么,导致T
受到约束,但使用static member
的以下代码可以按需工作:
type MyInterface = interface end
type EmptyType() = interface MyInterface
type RealType(v: int) =
member this.Value = v
interface MyInterface
type MyType<'T when 'T :> MyInterface>(element: 'T) =
static member Empty() = MyType(EmptyType())
member this.X = 0
[<EntryPoint>]
let main _ =
let a = MyType<_>.Empty()
let b = MyType(RealType(0))
0