我注意到在F#中静态方法比C#更受欢迎。在C#中,你总是通过调用实例方法来向集合中添加元素:
mySet.Add(elem);
但在 F# 中通常有一个等价的静态方法:
mySet.Add(elem)
// OR
Set.Add elem mySet
我经常在示例代码中看到这两种形式。在语义和功能上,它们对我来说完全相同,但作为一名C#程序员,使用实例方法会更自然。在F#中哪种风格更好?为什么呢?
我注意到在F#中静态方法比C#更受欢迎。在C#中,你总是通过调用实例方法来向集合中添加元素:
mySet.Add(elem);
但在 F# 中通常有一个等价的静态方法:
mySet.Add(elem)
// OR
Set.Add elem mySet
我经常在示例代码中看到这两种形式。在语义和功能上,它们对我来说完全相同,但作为一名C#程序员,使用实例方法会更自然。在F#中哪种风格更好?为什么呢?
myHigherOrderFunction (fun (x:MyType) -> x.myFunctionAsMethod)
myHigherOrderFunction MyType.myFunctionAsMethod
哪种方式更加优雅,更容易编写(也更容易阅读),并且几乎与发送常规let绑定函数时的语法相同。
实例方法需要类型的实例才能访问函数(方法),在面向对象编程中,这不是问题,因为您会考虑向对象发送消息,但在函数式编程中,仅有函数(没有实例)也是一等公民。
要访问静态方法,您需要指定类,可以将类视为带有函数的容器(如模块或命名空间)。
大多数标准F#类型都是不可变的。在使用不可变对象时,静态方法可以更好地描述正在发生的事情,例如:
mySet.Add(elem);
看起来mySet
被改变以包含elem
,而F#集合会返回一个新的mySet
。幸运的是,F#编译失败,以确保您不会犯这个错误,但仍然会导致混乱的代码。相比之下:
mySet |> Set.Add elm
这个东西在形式上很独特,看起来将会返回一些新的内容,而不会离原始内容太远。
虽然在F#中静态方法非常常见,但我发现对于组件开发来说,实例方法更有意义。
原因是,F#模块系统缺少functor。在其他ML风格(如SML或OCaml)中,您将组件开发为简单的模块。如果您稍后决定参数化该模块,则可以将其升级为functor而无需重写太多源代码。在F#中您不能这样做。
要在F#中创建参数化的“模块”,必须使用类并将方法转换为实例方法,在实例构造期间传递参数。不幸的是,从模块转换为类涉及相当多的机械但繁琐的源代码更改。因此,一位专业的组件程序员可能会选择默认使用类和实例方法,就像在C#中一样。这类似于有时在SML中采用的“仅限functor”样式。