【发布时间】:2016-12-31 17:05:07
【问题描述】:
我曾经认为Record 是(不可变)数据的容器,直到我读到一些启发性的读物。
鉴于函数可以被视为 F# 中的值,记录字段也可以保存函数值。这为状态封装提供了可能性。
module RecordFun =
type CounterRecord = {GetState : unit -> int ; Increment : unit -> unit}
// Constructor
let makeRecord() =
let count = ref 0
{GetState = (fun () -> !count) ; Increment = (fun () -> incr count)}
module ClassFun =
// Equivalent
type CounterClass() =
let count = ref 0
member x.GetState() = !count
member x.Increment() = incr count
用法
counter.GetState()
counter.Increment()
counter.GetState()
看来,除了继承之外,Class 没有什么可以做的,Record 和辅助函数是做不到的。其中plays better with functional concepts,比如模式匹配、类型推断、高阶函数、泛型相等……
进一步分析,Record 可以看作是由makeRecord() 构造函数实现的接口。应用(某种)关注点分离,其中makeRecord 函数中的逻辑可以更改而不会破坏合同,即记录字段。
当用与类型名称匹配的模块替换 makeRecord 函数时,这种分离变得明显(参考 Christmas Tree Record)。
module RecordFun =
type CounterRecord = {GetState : unit -> int ; Increment : unit -> unit}
// Module showing allowed operations
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module CounterRecord =
let private count = ref 0
let create () =
{GetState = (fun () -> !count) ; Increment = (fun () -> incr count)}
问:记录应该被视为数据的简单容器还是状态封装有意义?我们应该在哪里划线,什么时候应该使用Class 而不是Record?
请注意,链接帖子中的模型是纯模型,而上面的代码不是。
【问题讨论】:
-
有趣的问题;一般来说,限制在函数式语言中使用可变值是一个好主意。
-
people.csail.mit.edu/gregs/ll1-discuss-archive-html/…(向下滚动阅读关于 Qc Na 大师的故事)
-
我投票决定将此问题作为离题结束,因为它既是网站上其他问题的部分重复(参见其他链接),也至少部分基于意见,或是“太宽泛”。
-
This article 与您的问题有某种关联