接口与功能记录

时间:2014-09-22 20:34:55

标签: f#

练习有什么区别?你为什么要用另一个呢? 看起来这两种类型都可以用来解决同样的问题。

我的问题只涉及功能性F#代码。对于暴露给外部各方的F#组件,我发现Component Design Guidelines建议更喜欢接口方法而不是函数记录。

2 个答案:

答案 0 :(得分:22)

从概念上讲,函数的记录与接口非常相似,大多数时候,你可以使用它们来解决给定的问题(所以这是一个很好的和有效的问题)。

如果你只关注技术方面,那么最大的区别是接口可以有通用的方法。这是使用记录无法完成的事情 - 例如,无法定义与以下内容对应的简单函数记录:

type IFoo<'T> =
   abstract Bar<'R> : 'R -> 'T

然而,在实践中,我认为更重要的差异与互操作性和设计有关:

  • 接口与C#和其他.NET组件很好地互操作 (从C#构建一个F#函数记录将非常困难和丑陋)
  • 接口表达了不同的意图 - 它们是接口,可以满足并实现 另一方面,记录是函数的集合 创建
  • 如果您需要使用{ oldValue with NewFunction = newFunction }构造来替换一个函数,则记录很好。

一般情况下,当我需要保持某些状态时,我主要使用记录。一些数据结构的递归处理,我需要with构造。对于公共API,我认为使用接口和简单类比使用记录更好的抽象。

答案 1 :(得分:0)

记录与对象/接口之间有两个非常重要的区别。一个是记录没有“自我/这个”概念。另一个是记录支持with操作。结合起来,它会使功能记录难以实现服务引用。

例如,如果您要创建PrintX服务,则使用记录第一次尝试可能看起来像这样。

let createService x = { X = x; PrintX = fun () -> printfn x }
let myService = createService 1
let twoService = { myService with X = 2 }
twoService.PrintX()

它打印1,而不是2。确定可以说“好吧,不要这样做”。并且确保您可以通过关闭可变的x并在记录中提供SetX(x)函数来“修复”它。但是,该结构允许用户做一些荒谬的事情,这一事​​实表明,该结构本身不太适合代表您的意图。确实是一个圆钉的方孔。

所以我得到的认可是,对于只不过是各个部分的总和(包括独立功能的包),记录是完美的。但是对于一起形成一个连贯整体的事物,对象/接口确实更合适。