F#中的递归对象? [英] Recursive objects in F#?

查看:99
本文介绍了F#中的递归对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此F#代码段

    let rec reformat = new EventHandler(fun _ _ ->
        b.TextChanged.RemoveHandler reformat
        b |> ScrollParser.rewrite_contents_of_rtb
        b.TextChanged.AddHandler reformat
        )
    b.TextChanged.AddHandler reformat

导致以下警告:

traynote.fs(62,41):警告FS0040:将在运行时通过使用延迟引用来检查对正在定义的对象的此和其他递归引用的初始化是否健全.这是因为您要定义一个或多个递归对象,而不是递归函数.可以通过使用'#nowarn"40"'或'--nowarn:40'来禁止显示此警告.

traynote.fs(62,41): warning FS0040: This and other recursive references to the object(s) being defined will be checked for initialization-soundness at runtime through the use of a delayed reference. This is because you are defining one or more recursive objects, rather than recursive functions. This warning may be suppressed by using '#nowarn "40"' or '--nowarn:40'.

有没有一种方法可以重写代码来避免此警告?还是在F#中没有洁净的递归对象的方式?

Is there a way in which the code can be rewritten to avoid this warning? Or is there no kosher way of having recursive objects in F#?

推荐答案

您的代码是构造递归对象的完美方法.编译器会发出警告,因为它不能保证在初始化引用之前不会访问该引用(这将导致运行时错误).但是,如果您知道EventHandler在构造期间未调用提供的lambda函数(不会),则可以放心地忽略该警告.

Your code is a perfectly fine way to construct a recursive object. The compiler emits a warning, because it cannot guarantee that the reference won't be accessed before it is initialized (which would cause a runtime error). However, if you know that EventHandler does not call the provided lambda function during the construction (it does not), then you can safely ignore the warning.

举一个警告实际上表明有问题的示例,您可以尝试以下代码:

To give an example where the warning actually shows a problem, you can try the following code:

type Evil(f) =
  let n = f() 
  member x.N = n + 1

let rec e = Evil(fun () -> 
  printfn "%d" (e:Evil).N; 1)

Evil类在构造函数中采用一个函数,并在构造期间将其称为 .结果,lambda函数中的递归引用尝试在将e设置为值之前进行访问(并且您会收到运行时错误).但是,尤其是在使用事件处理程序时,这不是问题(当正确使用递归对象时,您会得到警告).

The Evil class takes a function in a constructor and calls it during the construction. As a result, the recursive reference in the lambda function tries to access e before it is set to a value (and you'll get a runtime error). However, especially when working with event handlers, this is not an issue (and you get the warnning when you're using recursive objects correctly).

如果要摆脱警告,可以使用显式的ref值和null重写代码,但是如果没有警告和带有更丑陋的代码:

If you want to get rid of the warning, you can rewrite the code using explicit ref values and using null, but then you'll be in the same danger of a runtime error, just without the warning and with uglier code:

let foo (evt:IEvent<_, _>) = 
  let eh = ref null
  eh := new EventHandler(fun _ _ -> 
    evt.RemoveHandler(!eh) )
  evt.AddHandler(!eh)

这篇关于F#中的递归对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆