在F#属性中使用lazy会阻止代码在不应该被评估时被评估吗?

f#

我有一个共同的模式:

type something =
    {
        ... a lot of stuff
    }

    member this.Description =
        "a string description of the content, can be long tables, etc"

我希望仅在需要时才对 Description 属性进行评估;在许多情况下,它不会被使用,但它可以(主要是根据用户的要求)。

我注意到即使不需要此代码,它也会导致对 Description 进行评估。所以我把代码移到了一个函数:Describe() 就解决了这个问题。

当我重构时,我正在重新审视这个。虽然它在实践中不会让任何事情变得更好,但我想知道是否有类似的东西:

member this.Describe =
    (lazy "the long to build text output").Value

会解决问题吗?因为惰性对象将被创建,但没有任何东西可以查询值本身。

那会可靠地工作吗?

回答

你声明属性的方式,它本质上是一个函数。它没有任何参数,但是每次有人尝试读取其值时,都会执行其主体中的代码。这就是属性在 .NET 中的一般工作方式。

这意味着无论您在其中放入什么,仍然会在每次访问时执行。尝试这个:

type T() =
  member this.Y = 
    printfn "Accessing value of Y"
    42

let t = T()
let a = t.Y
let b = t.Y
let c = t.Y

您应该会看到“Accessing value of Y”打印了 3 次。

如果你把整个东西都包起来也没关系lazy:你仍然Lazy在每次访问属性时构建一个全新的对象,然后立即读取它的值,从而导致它的主体进行评估。

如果你真的想 (1) 推迟评估直到需要和/或 (2) 缓存评估值,你应该在属性的主体之外创建Lazy对象,然后让属性读取它的值,以便它是被读取的同一个对象在每个属性访问:Lazy

type T() =
  let x = lazy (
    printfn "Calculating value of X"
    "expensive computation"
  )

  member this.X = x.Value

let t = T()
let a = t.X
let b = t.X
let c = t.X

这将只打印一次“计算 X 的值”。


以上是在F#属性中使用lazy会阻止代码在不应该被评估时被评估吗?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>