2012-07-13 77 views
9

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

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

+0

有点相关:http://stackoverflow.com/q/1805473/162396 – Daniel 2012-07-13 18:32:09

回答

12

可以滥用inline和成员的制约做鸭打字,这为您带来了mixins的一些好处。例如,你可以把这种Ruby代码(从this tutorial拍摄):

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关键字的问题,您可能会有几个模块定义whoAmI,最后一个模块会影响以前的模块。这样你就可以“混合”你想要的模块。 F#核心库使用与checked operators类似的方法。

2

在.NET框架中,最好使用扩展方法(类型扩展)模拟Ruby mixins。我不相信F#具有更接近mixin,traits或多重继承的特殊语言特征。

看到这个问题:How do I create an extension method (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())