在 F# 属性 中使用 lazy 会阻止代码在不应该被计算的时候被计算吗?
Will the use of lazy in an F# property prevent the code from being evaluated when it shouldn't?
我有一个共同的模式:
type something =
{
... a lot of stuff
}
member this.Description =
"a string description of the content, can be long tables, etc"
我希望仅在需要时评估描述 属性;在许多情况下,它不会被使用,但它可以(主要是根据用户的请求)。
我注意到这段代码会导致 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
您应该会看到打印了三次“访问 Y 的值”。
如果你把整个东西包装在 lazy
中也没关系:你仍然在每次访问 属性 时构建一个全新的 Lazy
对象,然后立即读取其值,从而导致其主体求值。
如果你真的想 (1) 延迟评估直到需要 and/or (2) 缓存评估值,你应该创建 Lazy
对象 outside 属性 的主体,然后让 属性 读取它的值,这样它就是在每次 属性 访问时读取的同一个 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 的值”。
我有一个共同的模式:
type something =
{
... a lot of stuff
}
member this.Description =
"a string description of the content, can be long tables, etc"
我希望仅在需要时评估描述 属性;在许多情况下,它不会被使用,但它可以(主要是根据用户的请求)。
我注意到这段代码会导致 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
您应该会看到打印了三次“访问 Y 的值”。
如果你把整个东西包装在 lazy
中也没关系:你仍然在每次访问 属性 时构建一个全新的 Lazy
对象,然后立即读取其值,从而导致其主体求值。
如果你真的想 (1) 延迟评估直到需要 and/or (2) 缓存评估值,你应该创建 Lazy
对象 outside 属性 的主体,然后让 属性 读取它的值,这样它就是在每次 属性 访问时读取的同一个 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 的值”。