创建辅助非泛型构造函数时 F# 中的编译器错误

Compiler error in F# when creating a secondary, non-generic constructor

我有一个泛型 class,其默认构造函数接受泛型类型的参数。创建第二个非泛型构造函数时,F# 编译器抱怨 This type parameter has been used in a way that constrains it to always be 'EmptyType',我根本不理解这个错误。为什么要约束?第二个构造函数与第一个构造函数的泛型 属性 有什么关系?

此示例显示错误(可在 F# playground 中重现)。请注意,只需注释第二个构造函数(第 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

不确定导致 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

构造函数不能是通用的。您的类型是通用的,但每个构造函数必须 return 定义它的确切类型。您不能有一个构造函数 return MyType<'t> 和另一个 return MyType<EmptyType>。如果在 MyType<'t> 上定义构造函数,则它必须 return MyType<'t> 而不能 return MyType<EmptyType>

当编译器看到其中一个构造函数 always returns MyType<EmptyType> 时,它断定类型参数 't 必须 总是等于EmptyType。正是在这个意义上,参数 't 被限制为 EmptyType,如错误消息所述。

没有办法让构造函数 return 的类型与其定义的类型不同。如果您必须专门构造 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()

此模式广泛用于泛型类型。例如,参见 OptionList