F# - “自填充”类型属性
本文关键字:类型 属性 自填充 填充 | 更新日期: 2023-09-27 18:37:01
在C#中,我可以有这个:
public class A {
...
private List<int> _items;
public List<int> Items{
get {
if (_items == null){
_items = DAL.FetchFromDB();
}
return _items;
}
}
}
这样,我可以初始化类 A,当我请求项目时
- 我保证无需明确填写列表即可获得它。
- 我避免重复调用数据库
F# 的等效构造是什么?我不确定如何制作一个执行此操作的类型...
我不一定要求可变列表;我想知道在 F# 中做这样的事情的标准形式是什么,因为我只是在学习语言。
正如ildjarn在上面的评论中指出的那样,你可以以等效的方式使用lazy
关键字:
type A () =
let items = lazy (DAL.FetchFromDB ())
member this.Items with get () = items.Value
但是,问题是它是"惯用的"F#,还是一般的"良好做法"?
Items
属性在引用上不透明(因为它不是确定性的),函数式编程往往非常强调引用透明度。
当然:F#不是一种纯粹的函数式语言;它是一种函数式第一语言。尽管如此,这意味着要充分利用它,您应该在设计中采用类似的功能优先方法。
你自己的代码越实用,你从 F# 中获得的价值就越大。
F# 代码的命令性、隐式或面向对象越多,从中获得的收益就越少。
因此,尝试将 C# 逐字转换为 F# 代码并不总是有意义的。你可以,但你会从中获得什么吗?
底线是可以将 C# 转换为类似于 F# 中的内容,但您应该考虑这是否是一个好主意。使用 lazy
关键字本身并没有错,但隐含性是我会重新考虑的。
这是对 F# 的一对一翻译:
type A() =
let mutable _items = null
member this.items
with get() =
if _items = null then _items <- DAL.FetchFromDB()
_items
let a = A()
let x = a.items // db access here
let y = a.items
有更好(和更短)的方法可以使用对象在 F# 中编写等效代码(请参阅另一个答案),但您根本不需要创建对象,您可以简单地定义一个函数,正如其他人已经指出的那样,您可以使用 lazy
关键字:
let items =
let v = lazy DAL.FetchFromDB()
fun () -> v.Value
let x = items() // db access here
let y = items()
或者直接使用标准的惰性值,我更喜欢这样,因为您在items
类型中明确表示您的值是惰性计算的,而不是将其隐藏在魔术对象属性或函数后面:
let items = lazy DAL.FetchFromDB()
let x = items.Value // db access here
let y = items.Value
所以现在items
的类型是Lazy<'List<'T>>
它总是告诉你值将是延迟计算的,除此之外,在这种情况下,代码实际上更短。