F# - "self-filling" 类型 属性
F# - "self-filling" type property
在 C# 中,我可以这样:
public class A {
...
private List<int> _items;
public List<int> Items{
get {
if (_items == null){
_items = DAL.FetchFromDB();
}
return _items;
}
}
}
这样,我可以实例化class A,当我请求Items时
- 我保证得到它,而无需明确填写列表。
- 我避免重复调用数据库
F# 的等效结构是什么?
我不确定如何制作这样的类型...
我不一定要可变列表;我想知道在 F# 中执行此类操作的标准形式是什么,因为我只是在学习这门语言。
正如 ildjarn 在上面的评论中指出的那样,您可以以等效的方式使用 lazy
关键字:
type A () =
let items = lazy (DAL.FetchFromDB ())
member this.Items with get () = items.Value
但是,问题是它是 'idiomatic' F#,还是一般的 'good practice'?
Items
属性 不是 referentially transparent(因为它不是确定性的),函数式编程往往非常强调引用透明性。
承认: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
类型中明确表示你的值是惰性计算的,而不是将它隐藏在 magic 对象 属性 或函数:
let items = lazy DAL.FetchFromDB()
let x = items.Value // db access here
let y = items.Value
所以现在 items
的类型是 Lazy<'List<'T>>
,它总是告诉你该值将被延迟计算,除此之外,在这种情况下代码实际上更短。
在 C# 中,我可以这样:
public class A {
...
private List<int> _items;
public List<int> Items{
get {
if (_items == null){
_items = DAL.FetchFromDB();
}
return _items;
}
}
}
这样,我可以实例化class A,当我请求Items时
- 我保证得到它,而无需明确填写列表。
- 我避免重复调用数据库
F# 的等效结构是什么? 我不确定如何制作这样的类型...
我不一定要可变列表;我想知道在 F# 中执行此类操作的标准形式是什么,因为我只是在学习这门语言。
正如 ildjarn 在上面的评论中指出的那样,您可以以等效的方式使用 lazy
关键字:
type A () =
let items = lazy (DAL.FetchFromDB ())
member this.Items with get () = items.Value
但是,问题是它是 'idiomatic' F#,还是一般的 'good practice'?
Items
属性 不是 referentially transparent(因为它不是确定性的),函数式编程往往非常强调引用透明性。
承认: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
类型中明确表示你的值是惰性计算的,而不是将它隐藏在 magic 对象 属性 或函数:
let items = lazy DAL.FetchFromDB()
let x = items.Value // db access here
let y = items.Value
所以现在 items
的类型是 Lazy<'List<'T>>
,它总是告诉你该值将被延迟计算,除此之外,在这种情况下代码实际上更短。