4

在这个问题的上下文中发现这种看似不一致的行为可以在 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

谁能解释观察到的行为是错误还是功能?

更新: 这个相关答案传达了 F# 开发团队的确认,即到目前为止,在处理具有ParamArray属性的泛型类型参数时存在一个错误。

4

1 回答 1

5

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

在您的示例中,这在第二种情况下是可能的:

Generic.Echo [|0|]

编译器推断'Tint这样,因此您将传递int[]给类型的参数,int[]因此编译器会忽略ParamArray属性,并且该方法仅获取包含0.

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

Heterogeneous.Echo [|0|]

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

如果你调用Heterogeneous.Echowithobj[]作为参数,那么它的行为类似于Generic.Echo. 例如:

Heterogeneous.Echo [| box 0 |]

如果你想深入了解,你可以看第 14.4 节。的F# 语言规范。但是,重载解决规则非常复杂,因此我没有解释此行为的确切参考 - 只是上面的非正式解释。

于 2012-06-17T20:08:50.463 回答