svi*_*ick 6 f# delegates ref byref
在正常情况下,可以通过调用new DelegateType函数并将函数作为参数传递,将F#函数转换为委托.但是当委托包含byref参数时,这是不可能的.例如代码:
type ActionByRef<'a> = delegate of 'a byref -> unit
let f (x:double byref) =
x <- 6.0
let x = ref 42.0
let d = new ActionByRef<_>(f)
Run Code Online (Sandbox Code Playgroud)
不会编译,给出以下错误:
此函数值用于构造其签名包含byref参数的委托类型.您必须使用带有1个参数的显式lambda表达式.
出现错误后,修改要使用的代码
let d = new ActionByRef<_>(fun x -> f(&x))
Run Code Online (Sandbox Code Playgroud)
作品.但我的问题是:为什么这有必要?为什么F#不允许从命名函数转换到此委托,但是从lambda转换是好的?
在研究另一个问题时,我发现了这种行为.我意识到byref只是为了与其他.Net语言兼容.
Tom*_*cek 10
我认为问题是它byref<'T>不是F#中的实际类型 - 它看起来像一个类型(使语言更简单),但它被编译为标记有out标志的参数.这意味着byref<'T>只能在编译器实际使用该out标志的地方使用.
函数值的问题在于您可以通过部分应用来构造函数:
let foo (n:int) (b:byref<int>) =
b <- n
Run Code Online (Sandbox Code Playgroud)
当您foo作为参数传递给委托构造函数时,它是部分应用程序(没有参数)的特定情况,但部分应用程序实际上需要构造一个新方法,然后将其提供给委托:
type IntRefAction = delegate of byref<int> -> unit
let ac = IntRefAction(foo 5)
Run Code Online (Sandbox Code Playgroud)
编译器可以很聪明并使用byref参数(或out标志)生成新方法,然后通过引用传递给实际函数,但通常,当您不使用fun ... -> ...语法时,将有其他编译器生成的方法.处理这会增加复杂性,我认为这是一个相对罕见的情况,所以F#编译器不这样做,并要求你更明确......