我以为F#函数和System.Func之间的转换必须手动完成,但似乎在某些情况下编译器(有时)会为您执行此操作。当出现错误时,错误消息也不准确:
module Foo =
let dict = new System.Collections.Generic.Dictionary<string, System.Func<obj,obj>>()
let f (x:obj) = x
do
// Question 1: why does this compile without explicit type conversion?
dict.["foo"] <- fun (x:obj) -> x
// Question 2: given that the above line compiles, why does this fail?
dict.["bar"] <- f
最后一行无法编译,错误是:
This expression was expected to have type
System.Func<obj,obj>
but here has type
'a -> obj
显然,该函数f
没有的签名'a > obj
。如果F#3.1编译器对第一个字典分配感到满意,那么为什么不对第二个字典分配满意呢?
规范中应对此进行解释的部分是8.13.7成员调用时的类型定向转换。简而言之,当调用成员时,将应用从F#函数到委托的自动转换。不幸的是,规格还不清楚。从措辞上看,这种转换似乎可以适用于任何函数表达式,但实际上,它似乎仅适用于匿名函数表达式。
规范也有点过时了。在F#3.0中,类型定向转换还允许转换为System.Linq.Expressions.Expression<SomeDelegateType>
。
编辑
在查看过去与F#团队的往来信件时,我想我已经跟踪了如何将转换应用于非语法功能表达式。为了完整起见,这里将其包括在内,但这是一个奇怪的特殊情况,因此对于大多数目的,您可能应该考虑以下规则:仅语法函数将应用类型定向转换。
例外是重载解析会导致转换函数类型的任意表达式;第14.4节“方法应用程序解析”部分对此进行了部分解释,尽管它非常密集并且仍然不十分清楚。基本上,仅当有多个重载时才对参数表达式进行详细说明。当只有一个候选方法时,将针对未详细说明的参数声明参数类型(请注意:就转换是否适用而言,这实际上并不重要,但凭经验而言确实重要)。这是一个演示此异常的示例:
type T =
static member M(i:int) = "first overload"
static member M(f:System.Func<int,int>) = "second overload"
let f i = i + 1
T.M f |> printfn "%s"
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句