Rubyでミックスインを実現したり、F#でScalaのトレイトを実現したりする方法はありますか?
私が欲しいのは、基本的に1つのモジュールを別のモジュールにコピーして、他のモジュールの機能を共有するが、変更のために閉じられるようにすることです。または、OOPの考え方ですが、親オブジェクトを変更できないことを除いて、多重継承が必要です。
Rubyでミックスインを実現したり、F#でScalaのトレイトを実現したりする方法はありますか?
私が欲しいのは、基本的に1つのモジュールを別のモジュールにコピーして、他のモジュールの機能を共有するが、変更のために閉じられるようにすることです。または、OOPの考え方ですが、親オブジェクトを変更できないことを除いて、多重継承が必要です。
ダックタイピングを行うためにメンバーの制約を悪用することができinline
ます。これにより、ミックスインの利点のいくつかが得られます。たとえば、この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
いくつかのモジュールを定義することができ、最後に編集whoAmI
したものが前のモジュールをシャドウイングします。open
このようにして、必要なモジュールを「ミックスイン」することができます。F#コアライブラリは、チェックされた演算子を使用した同様のアプローチを使用します。
Rubyミックスインは、.NET Frameworkの拡張メソッド(型拡張)を使用してエミュレートするのが最適です。F#には、ミックスイン、特性、または多重継承にさらに類似した特別な言語機能があるとは思いません。
この質問を参照してください:拡張メソッド(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())