我注意到静态方法在F#中比C#更受欢迎。在C#中,您总是通过调用实例方法将一个元素添加到集合中:
mySet.Add(elem);
但是在F#中通常有一个等效的静态方法:
mySet.Add(elem)
// OR
Set.Add elem mySet
我在样本中经常看到后一种形式。在我看来,两者在语义和功能上完全相同,但是来自C#背景,使用实例方法感觉更自然。在F#中哪种风格更好?为什么?
答案 0 :(得分:8)
除了与类型推断相关的答案中提到的原因之外,在函数式中更自然地将函数作为参数发送。 如果它是一个实例方法,你将不得不写这样的东西:
myHigherOrderFunction (fun (x:MyType) -> x.myFunctionAsMethod)
但如果它被定义为静态方法,你可以写:
myHigherOrderFunction MyType.myFunctionAsMethod
更优雅,更容易编写(也可以阅读),并且与发送常规let绑定函数时的语法几乎相同。
实例方法需要类型的实例才能访问函数(方法),在OOP中这不是问题,因为您认为在向对象发送消息但在FP中,单独的函数(没有实例)是第一个班级公民。
要访问需要指定Class的静态方法,可以将Class视为一种带有函数的容器(如模块或命名空间)。
答案 1 :(得分:5)
大多数标准F#类型都是不可变的。使用不可变对象时,静态方法可以更好地描述正在发生的事情,例如:
mySet.Add(elem);
当F#集合返回新的mySet
时,elem
似乎已变异以包含mySet
。幸运的是,F#无法编译以确保您不会犯这个错误,它仍然会导致令人困惑的代码。相反:
mySet |> Set.Add elm
在形式上有所区别,看起来它会返回一些新的东西,而不会离原版太远。
答案 2 :(得分:2)
虽然F#中的静态方法很常见,但我发现实例方法对组件开发很有意义。
原因? F#模块系统缺乏仿函数。在其他类型的ML中,例如SML或OCaml,您可以将组件开发为简单模块。如果您以后决定参数化模块,则可以将其升级为仿函数,而无需重写太多的源代码。在F#你不能。
要在F#中创建参数化的“模块”,您必须求助于一个类并将您的方法转换为实例方法,并在实例构造期间传入参数。不幸的是,从模块到类需要相当多的机械但令人讨厌的源代码更改。因此,默认情况下,硬核组件程序员可能会选择使用类和实例方法,就像在C#中一样。这让人想起SML中有时使用的“仅限仿真器”的风格。
答案 3 :(得分:0)
在f#中作为函数式语言更加本地化,以分离不可变的变量和作为操作的函数。这个函数类似于c#中的静态方法,但是c#方法的功能有一个优点。这是部分应用。你可以传递函数一些(不是所有)参数,这个参数的一部分函数将是需要其他参数的新函数。