クラス<< Rubyの自己イディオム


873

Rubyでは何をしclass << selfますか?


35
Yehuda Katz:yehudakatz.com/2009/11/15/… およびYugui
Andrei

3
ここにもう1つの非常に優れた記事:integralist.co.uk/posts/eigenclass.html
Saman Mohamadi

2
これはモジュールの内部で見られますが、それによって違うのでしょうか?github.com/ruby/rake/blob/master/lib/rake/rake_module.rb
William Entriken

@FullDecent Rubyのすべてがモジュールやクラスを含むオブジェクトであるため、違いはありません。
アーロン

1
参照してくださいgithub.com/defunkt/metaid/blob/master/metaid.rb それは「明らかにメタクラスを見て」と行くviewsourcecode.org/why/hacking/seeingMetaclassesClearly.html
ダグラス・G.アレン

回答:


912

まず、class << foo構文はfooのシングルトンクラス(固有クラス)を開きます。これにより、その特定のオブジェクトで呼び出されるメソッドの動作を特化できます。

a = 'foo'
class << a
  def inspect
    '"bar"'
  end
end
a.inspect   # => "bar"

a = 'foo'   # new object, new singleton class
a.inspect   # => "foo"

ここで、質問に答えるには、のシングルトンクラスをclass << self開きself、現在のselfオブジェクト(クラスまたはモジュール本体内のクラスまたはモジュール自体)に対してメソッドを再定義できるようにします。通常、これはクラス/モジュール(「静的」)メソッドの定義に使用されます。

class String
  class << self
    def value_of obj
      obj.to_s
    end
  end
end

String.value_of 42   # => "42"

これは略記として書くこともできます:

class String
  def self.value_of obj
    obj.to_s
  end
end

またはさらに短い:

def String.value_of obj
  obj.to_s
end

関数定義内で、関数selfが呼び出されているオブジェクトを参照します。この場合、class << selfそのオブジェクトのシングルトンクラスを開きます。その1つの使用法は、貧乏人の状態機械を実装することです。

class StateMachineExample
  def process obj
    process_hook obj
  end

private
  def process_state_1 obj
    # ...
    class << self
      alias process_hook process_state_2
    end
  end

  def process_state_2 obj
    # ...
    class << self
      alias process_hook process_state_1
    end
  end

  # Set up initial state
  alias process_hook process_state_1
end

したがって、上記の例でStateMachineExampleは、の各インスタンスがにprocess_hookエイリアスされてprocess_state_1いますが、後者では、process_hookself他のStateMachineExampleインスタンスに影響を与えずに)をに再定義できることに注意してくださいprocess_state_2。したがって、呼び出し元がprocessメソッド(redefinableを呼び出すprocess_hook)を呼び出すたびに、その状態に応じて動作が変化します。


22
@ヨルク:編集の+1(SOが編集を賛成する機能を提供することを願っています。これは、class << selfクラス/モジュールメソッドを作成するためののより一般的な使用方法です。私はおそらくclass << selfもっと慣用的な使用法であるため、その使用法を拡張します。
Chris Jester-Young

4
gsub!( "eigenclass"、 "singleton class")、次のメソッドを参照redmine.ruby-lang.org/repositories/revision/1?rev=27022 –Marc
AndréLafortune

4
本当にを参照するために混乱を招くasingleton_classため、a(変更後のクラスのはinspect)独特の変種であるStringクラス。シングルトンStringクラスを変更すると、他のすべてのStringインスタンスに影響します。さらに奇妙なのは、後で再び開いStringて再定義したinspect場合aでも、新しい変更が反映されることです。
Old Pro

1
@OldPro私は今でも(私は信じている)Matzもそうであるように、eigenclassという名前を好みます。しかし、みんなを満足させることはできないと思います。
Chris Jester-Young

5
「オブジェクトのシングルトンクラスを開く」という表現は、これまで何度も読んだことがあり、あいまいです。私の知る限りでは、Rubyのドキュメントのどこにも、定義されたクラスを「開く」ことはできません。いclass << self以上の値よりも平均何をselfブロックの範囲内でシングルトンクラスに等しく設定されていますか?
Cary Swoveland

34

私は約スーパー簡単な説明を見つけclass << selfEigenclassおよび方法の異なるタイプを。

Rubyには、クラスに適用できる3つのタイプのメソッドがあります。

  1. インスタンスメソッド
  2. シングルトン法
  3. クラスメソッド

インスタンスメソッドとクラスメソッドは、他のプログラミング言語での同義語とほとんど同じです。

class Foo  
  def an_instance_method  
    puts "I am an instance method"  
  end  
  def self.a_class_method  
    puts "I am a class method"  
  end  
end

foo = Foo.new

def foo.a_singleton_method
  puts "I am a singletone method"
end

にアクセスする別の方法 Eigenclass(シングルトンメソッドを含む)、次の構文(class <<)を使用することです。

foo = Foo.new

class << foo
  def a_singleton_method
    puts "I am a singleton method"
  end
end

これで、このコンテキストのselfクラスFoo自体であるシングルトンメソッドを定義できます。

class Foo
  class << self
    def a_singleton_and_class_method
      puts "I am a singleton method for self and a class method for Foo"
    end
  end
end

4
シングルトンメソッドとクラスメソッドは実際には同じですが、どちらもシングルトンクラスに存在します。foo.singleton_class.instance_methods(false)確認に使用できます。
デイモンユアン

22

通常、インスタンスメソッドはグローバルメソッドです。つまり、それらが定義されたクラスのすべてのインスタンスで使用できます。対照的に、シングルトンメソッドは単一のオブジェクトに実装されます。

Rubyはメソッドをクラスに格納し、すべてのメソッドはクラスに関連付けられている必要があります。シングルトンメソッドが定義されているオブジェクトはクラスではありません(クラスのインスタンスです)。クラスだけがメソッドを格納できる場合、オブジェクトはどのようにシングルトンメソッドを格納できますか?シングルトンメソッドが作成されると、Rubyはそのメソッドを格納する匿名クラスを自動的に作成します。これらの匿名クラスはメタクラスと呼ばれ、シングルトンクラスまたは固有クラスとも呼ばれます。シングルトンメソッドはメタクラスに関連付けられ、メタクラスはシングルトンメソッドが定義されたオブジェクトに関連付けられます。

1つのオブジェクト内で複数のシングルトンメソッドが定義されている場合、それらはすべて同じメタクラスに格納されます。

class Zen
end

z1 = Zen.new
z2 = Zen.new

class << z1
  def say_hello
    puts "Hello!"
  end
end

z1.say_hello    # Output: Hello!
z2.say_hello    # Output: NoMethodError: undefined method `say_hello'…

上記の例では、クラス<< z1は、z1オブジェクトのメタクラスを指すように現在の自己を変更します。次に、メタクラス内でsay_helloメソッドを定義します。

クラスもオブジェクトです(Classと呼ばれる組み込みクラスのインスタンス)。クラスメソッドは、クラスオブジェクトに関連付けられたシングルトンメソッドにすぎません。

class Zabuton
  class << self
    def stuff
      puts "Stuffing zabuton…"
    end
  end
end

すべてのオブジェクトはメタクラスを持つことができます。つまり、クラスはメタクラスを持つこともできます。上記の例では、クラス<< selfはZabutonクラスのメタクラスを指すようにselfを変更します。明示的なレシーバー(メソッドが定義されるクラス/オブジェクト)なしでメソッドが定義されると、現在のスコープ、つまりselfの現在の値内で暗黙的に定義されます。したがって、スタッフメソッドはZabutonクラスのメタクラス内で定義されます。上記の例は、クラスメソッドを定義するもう1つの方法です。私見、コードを理解しやすくするため、def self.my_new_clas_method構文を使用してクラスメソッドを定義することをお勧めします。上記の例は、クラス<<自己構文に遭遇したときに何が起きているかを理解するために含まれています。

Ruby Classesに関する追加情報はこの投稿にあります。


15

クラス<<の内容:

class Hi
  self #=> Hi
  class << self #same as 'class << Hi'
    self #=> #<Class:Hi>
    self == Hi.singleton_class #=> true
  end
end

[ self == thing.singleton_class そのブロックのコンテキストで作成します]


Thing.singleton_classとは何ですか?

hi = String.new
def hi.a
end

hi.class.instance_methods.include? :a #=> false
hi.singleton_class.instance_methods.include? :a #=> true

hiオブジェクトは#methodsから継承し#singleton_class.instance_methods、次にから継承します#class.instance_methods
ここでは、与えたhiシングルトンクラスのインスタンスメソッドを:a。代わりにクラス<< hiを使用して行うことができます。
hiさんは#singleton_class、すべてのインスタンスメソッドがあるhis 'を#class(持っている、そしておそらくいくつかのより多くの:aここでは)。

【もののインスタンスメソッド #class #singleton_class の事に直接適用することができます。rubyがthing.aを見つけると、最初に:aメソッド定義をthing.singleton_class.instance_methodsで探し、次にthing.class.instance_methodsで探します]


ちなみに、オブジェクトのシングルトンクラス == metaclass == eigenclassを呼び出します。


3

А シングルトン法は、単一のオブジェクトに対してのみ定義されるメソッドです。

例:

class SomeClass
  class << self
    def test
    end
  end
end

test_obj = SomeClass.new

def test_obj.test_2
end

class << test_obj
  def test_3
  end
end

puts "Singleton's methods of SomeClass"
puts SomeClass.singleton_methods
puts '------------------------------------------'
puts "Singleton's methods of test_obj"
puts test_obj.singleton_methods

SomeClassのシングルトンのメソッド

テスト


test_objのシングルトンのメソッド

test_2

test_3


1

実際、RubyプロジェクトのC拡張機能を作成する場合、Moduleメソッドを定義する方法は1つしかありません。

rb_define_singleton_method

この自営業は他のあらゆる種類の質問を開くだけなので、各部分を検索することでより良い結果が得られることを知っています。

最初にオブジェクト。

foo = Object.new

fooのメソッドを作成できますか?

承知しました

def foo.hello
 'hello'
end

どうすればよいですか?

foo.hello
 ==>"hello"

ちょうど別のオブジェクト。

foo.methods

すべてのObjectメソッドと新しいメソッドを取得します。

def foo.self
 self
end

foo.self

fooオブジェクトだけです。

ClassやModuleなどの他のオブジェクトからfooを作成するとどうなるかを確認してください。すべての回答の例を試すのは良いことですが、コードの記述方法で何が起こっているのかを本当に理解するには、さまざまなアイデアや概念を使用する必要があります。これで、検討すべき用語がたくさんあります。

シングルトン、クラス、モジュール、自己、オブジェクト、および固有クラスが登場しましたが、Rubyはオブジェクトモデルにそのような名前を付けていません。メタクラスに似ています。リチャードまたは__whyがここでアイデアを示します。 http://viewsourcecode.org/why/hacking/seeingMetaclassesClearly.html そして、もしあなたがたら、検索でRubyオブジェクトモデルを調べてみてください。私がYouTubeで知っている2つの動画は、Dave ThomasとPeter Cooperです。彼らはその概念も説明しようとしています。Daveを取得するのに長い時間がかかったので、心配しないでください。私もまだそれに取り組んでいます。なぜ私はここにいるのですか?ご質問ありがとうございます。また、標準ライブラリもご覧ください。参考までに、シングルトンモジュールがあります。

これはかなり良いです。 https://www.youtube.com/watch?v=i4uiyWA8eFk

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.