2012-07-13 18 views
9

Rubyでmixinを実現する方法やF#でScalaの特性を得る方法はありますか?mixin or trait in F#

私が望むのは、基本的にあるモジュールを別のモジュールにコピーして他のモジュールの機能を共有することですが、変更はできません。または、OOPの考え方では、親オブジェクトを変更できないことを除いて、複数の継承が必要です。

+0

多少の関連性:http://stackoverflow.com/q/1805473/162396 – Daniel

答えて

12

あなたはアヒルを行うにはinlineとメンバー制約を乱用することができますミックスインの利点のいくつかを得るタイピング。これに

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" 

それは必要としないの拡張メソッドの上に(議論の余地)利点があるたとえば、(this tutorialから取られた)このRubyコードを変換することができ共通基本クラスまたはインタフェースopenキーワードについての以前の質問に関しては、whoAmIを定義するいくつかのモジュールを持つことができ、最後にopenが1つ前のモジュールをシャドウします。そのようにして、あなたが望むモジュールを「ミックスイン」することができます。 F#コアライブラリはchecked operatorsで同様のアプローチを使用します。

2

Rubyミックスインは、.NET Frameworkの拡張メソッド(型拡張子)で最もよくエミュレートされます。私は、F#にミックスイン、形質、または複数の継承に酷似した特別な言語機能があるとは思わない。

この質問を参照してください: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())