2

这是两个 F# 场景。我有一个抽象类:

type IAbstractObj =
    abstract DoSomething : bool -> bool

场景一:

我将接口实现为一种类型:

type ConcreteObj = 
    interface IAbstractObj with
        member this.DoSomething bool = true

然后通过实例化在应用程序中使用它:

let foo = new ConcreteObj();

场景二:

我用 let 绑定绑定了该类型的一个实例,并将其用作“自由函数持有者”:

let ConcreteObj = {
    new IAbstractObj with
        member this.DoSomething bool = true
}

并像这样使用它:

let foo = ConcreteObj

这些用法之间有什么区别?在任何一种情况下,类型都不需要保存任何额外的运行时状态。

  • 会有性能差异(微小)吗?对于包含“let”绑定的模块,内存是否只分配给在应用程序的其他部分实际评估的绑定?
  • 场景 1 会分配少量内存来保存指向实例的指针(即使它是无状态的)?

这对我的申请相当重要。我为不包含任何实例状态的验证器和序列化器使用了许多接口。以我的 C# 背景,我习惯于创建一个继承接口的类的实例,即使它具有无参数的构造函数并且显然只是本质上静态函数的持有者。

4

2 回答 2

3

两者之间的主要区别在于对象表达式具有其实现的接口或抽象类的静态类型。然而,基于类的接口实现是显式的,需要强制转换才能访问接口成员。

对于简单的接口实现,对象表达式通常是比类更好的选择。

(FWIW,我认为您的性能问题无关紧要。)

于 2013-09-19T19:09:44.013 回答
3

有一个比其中任何一个都更惯用的选项。不要为每个选项创建一个新类型,只需创建一个记录类型,它有两个成员,它们是函数。您几乎在评论中自己定义了它:

type serializer<'a, 'b> = 
    { Serialize : 'a -> 'a Option
      Deserialize: 'b -> 'b Option}

let concrete = { Serialize = (fun (x)->Some(x)); Deserialize = (fun (x)->Some(x)) }

因此,无论消耗什么,都应该采取serializer.

于 2013-09-19T19:32:54.500 回答