gpt4 book ai didi

oop - F# 记录与类

转载 作者:行者123 更新时间:2023-12-04 03:10:49 25 4
gpt4 key购买 nike

我曾经想到一个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() 实现的接口(interface)构造函数。应用(某种)关注点分离,其中 makeRecord 中的逻辑可以更改功能而不会有违反契约(Contract)的风险,即记录字段。

更换 makeRecord 时,这种分离变得明显。具有与类型名称匹配的模块的函数(引用圣诞节 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 ?

请注意,链接帖子中的模型是纯模型,而上面的代码则不是。

最佳答案

我认为这个问题没有统一的答案。确实,记录和类在某些潜在用途上重叠,您可以选择其中任何一个。

值得牢记的一个区别是编译器会自动为记录生成结构相等和结构比较,这是您无法免费获得的类的东西。这就是为什么记录是“数据类型”的明显选择。

在记录和类之间进行选择时,我倾向于遵循的规则是:

  • 使用数据类型的记录(免费获得结构平等)
  • 当我想提供 C# 友好或 .NET 样式的公共(public) API(例如,带有可选参数)时,请使用类。你也可以用记录来做到这一点,但我发现类更直接
  • 为本地使用的类型使用记录 - 我认为您通常最终直接使用记录(例如创建它们),因此添加/删除字段需要更多工作。对于仅在单个文件中使用的记录,这不是问题。
  • 如果我需要使用 { ... with ... } 创建克隆,请使用记录句法。如果您正在编写一些递归处理并且需要保持状态,这特别好。

  • 我不认为每个人都会同意这一点,它并没有涵盖所有选择 - 但一般来说,使用记录作为数据和本地类型和类作为其余部分似乎是在两者之间进行选择的合理方法。

    关于oop - F# 记录与类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41410296/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com