F#中通用ParamArray参数的处理不一致

Gen*_*ski 4 .net f#

这个问题的背景下被发现这个看似不一致的行为可以在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
Run Code Online (Sandbox Code Playgroud)

用法:返回:

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
Run Code Online (Sandbox Code Playgroud)

任何人都可以解释观察到的行为是否是一个错误或功能?

更新: 这个相关的答案传达了F#开发团队的一个确认,即现在在处理带ParamArray属性的泛型类型参数时存在错误.

Tom*_*cek 5

这种情况有点令人困惑,因为当您使用数组作为标记的参数的实际参数时ParamArray,语言会尝试将其解释为将数组传递给正常的数组类型参数(因此ParamArray如果可能,它会忽略该属性).

在您的示例中,在第二种情况下可以这样做:

Generic.Echo [|0|]
Run Code Online (Sandbox Code Playgroud)

编译器推断出这'Tint因为你传递int[]给类型的参数,int[]所以编译器忽略ParamArray属性,方法只是得到一个包含的数组0.

在另一种情况下,这是不可能的:

Heterogeneous.Echo [|0|]
Run Code Online (Sandbox Code Playgroud)

该方法需要一个类型的参数obj[]和参数的类型int[],因此这两种类型不能统一(关键是编译器不会自动转换int[]obj[]).由于这是不可能的,它会考虑该ParamArray属性并尝试转换int[]obj并将其作为成员传递ParamArray- 这是编译器可以自动执行的转换,因此您可以获得所描述的结果.

如果你打电话Heterogeneous.Echoobj[]作为参数,那么它会表现类似Generic.Echo.例如:

Heterogeneous.Echo [| box 0 |]
Run Code Online (Sandbox Code Playgroud)

如果您想了解详细信息,请参阅第14.4节.的F#语言规范.但是,重载决策规则非常复杂,所以我没有一个解释这种行为的确切参考 - 只是上面的非正式解释.