在this question看似这样的背景下被发现 不一致的行为可以在F#2.0和F#3.0 RC中再现:
type Heterogeneous =
static member Echo([<ParamArray>] args: Object[]) = args
type Generic =
static member Echo<'T>([<ParamArray>] args: 'T[]) = args
用法:返回:
Heterogeneous.Echo 0 // [|0|] OK
Generic.Echo 0 // [|0|] OK
Heterogeneous.Echo (0,1) // [|0; 1|] OK
Generic.Echo (0,1) // [|0; 1|] OK
Heterogeneous.Echo [|0|] // [|[|0|]|] OK?
Generic.Echo [|0|] // [|0|] OOPS!!
Heterogeneous.Echo ([|0|],[|1|])) // [|[|0|]; [|1|]|] OK
Generic.Echo ([|0|],[|1|])) // [|[|0|]; [|1|]|] OK
任何人都可以解释观察到的行为是否是错误或功能?
更新
这个related answer传达了F#开发团队的确认,截至目前,在处理具有ParamArray
属性的泛型类型参数时存在一个错误。
答案 0 :(得分:5)
这种情况有点令人困惑,因为当您使用数组作为标记为ParamArray
的参数的实际参数时,该语言会尝试将其解释为将数组传递给正常的数组类型参数(所以如果可能,它会忽略ParamArray
属性。
在您的示例中,在第二种情况下可以这样做:
Generic.Echo [|0|]
编译器推断'T
为int
,因此您将int[]
传递给int[]
类型的参数,因此编译器会忽略ParamArray
属性并且该方法只是获取包含0
的数组。
在另一种情况下,这是不可能的:
Heterogeneous.Echo [|0|]
该方法需要一个obj[]
类型的参数,参数类型为int[]
,因此这两种类型无法统一(关键是编译器不会自动转换{{1}到int[]
)。由于这是不可能的,它会考虑obj[]
属性并尝试将ParamArray
转换为int[]
并将其作为obj
的成员传递 - 这是编译器的转换可以自动执行,因此您可以获得所描述的结果。
如果您使用ParamArray
作为参数调用Heterogeneous.Echo
,那么它的行为与obj[]
类似。例如:
Generic.Echo
如果您想了解详细信息,请参阅第14.4节。的F# language specification。但是,重载决策规则非常复杂,所以我没有一个确切的参考来解释这种行为 - 只是上面的非正式解释。