11

有没有办法在 Ruby 中实现 mixin 或在 F# 中的 Scala 中实现 trait?

我想要的是基本上将一个模块复制到另一个模块中,以便它共享其他模块的功能但关闭以供修改。或者,一种OOP的思考方式,除了不能修改父对象外,我想要多重继承。

4

2 回答 2

14

你可以滥用inline和成员约束来做鸭子类型,这让你获得了 mixins 的一些好处。例如,您可以翻译这段 Ruby 代码(取自本教程):

module Debug
  def whoAmI?
    "#{self.type.name} (\##{self.id}): #{self.to_s}"
  end
end
class Phonograph
  include Debug
  # ...
end
class EightTrack
  include Debug
  # ...
end
ph = Phonograph.new("West End Blues")
et = EightTrack.new("Surrealistic Pillow")
ph.whoAmI?  »   "Phonograph (#537766170): West End Blues"
et.whoAmI?  »   "EightTrack (#537765860): Surrealistic Pillow"

对此:

type Phonograph(id, name) =
  member x.Id : int = id
  override x.ToString() = name

type EightTrack(id, name) =
  member x.Id : int = id
  override x.ToString() = name

module Debug =
  let inline whoAmI x =
    sprintf "%s (%d) : %s" 
      (^T : (member GetType : unit -> Type) x).Name
      (^T : (member Id : int with get) x)
      (^T : (member ToString : unit -> string) x)

let ph = Phonograph(537766170, "West End Blues")
let et = EightTrack(537765860, "Surrealistic Pillow")

Debug.whoAmI ph //"Phonograph (537766170) : West End Blues"
Debug.whoAmI et //"EightTrack (537765860) : Surrealistic Pillow"

与不需要公共基类或接口的扩展方法相比,它具有(有争议的)优势。关于您之前关于open关键字的问题,您可以定义几个模块whoAmIopen最后一个会影响以前的模块。通过这种方式,您可以“混入”您想要的模块。F# 核心库使用与检查运算符类似的方法。

于 2012-07-13T20:30:22.377 回答
2

Ruby mixin 最好用 .NET 框架中的扩展方法(类型扩展)来模拟。我不相信 F# 有任何更类似于 mixin、特征或多重继承的特殊语言特性。

请参阅此问题:如何创建扩展方法 (F#)?

而这个描述:http: //msdn.microsoft.com/en-us/library/dd233211.aspx

为了速度,这是 MSDN 上给出的示例:

module MyModule1 =

    // Define a type.
    type MyClass() =
      member this.F() = 100

    // Define type extension.
    type MyClass with
       member this.G() = 200

module MyModule2 =
   let function1 (obj1: MyModule1.MyClass) =
      // Call an ordinary method.
      printfn "%d" (obj1.F())
      // Call the extension method.
      printfn "%d" (obj1.G())
于 2012-07-13T18:32:51.823 回答