このディスカッション に触発されて、グーグルをした後、Rubyのメソッドに関する非常に単純な質問に対する答えを見つけることができませんでした:メソッドはオブジェクトかどうか?
ここ と そこ という意見がありますが、詳細な説明を聞きたいと思います。
メソッド名を取得してMethod
インスタンスを返すObject#method
メソッドを知っていますが、一方で、ブロックを使用してそれらをProc
インスタンスにすることができる同様のことがあり、ブロックはそうではありません。 tオブジェクトでは、メソッドの違いは何ですか?
メソッドはRubyの構文の基本的な部分ですが、Rubyプログラムが操作できる値ではありません。つまり、Rubyのメソッドはオブジェクトではありません文字列、数値、配列のように。ただし、特定のメソッドを表すMethodオブジェクトを取得することは可能であり、Methodオブジェクトを介して間接的にメソッドを呼び出すことができます。
From The Rubyプログラミング言語 :
あなたは本当に言うことはできません。
メソッドにアクセスする唯一の方法は、#method
メッセージをオブジェクトに送信することです。これにより、Method
オブジェクトが返されます。しかし、そのMethod
オブジェクトはメソッド自体ですか?それとも、メソッドのラッパーですか?それとも、元のメソッドの変換バージョンですか?
わからない:メソッドを見たい場合は、#method
を呼び出す必要があります。その時点で、間違いなくwillオブジェクトを取得します。それが何であったか前あなたは#method
と呼んだが、見ることができないので、分からない。
いくつかのデータポイント:Rubyでは、すべてが値を返します。 def
は何を返しますか? 常にはnil
オブジェクトではなく、Method
を返します。そしてdefine_method
? Proc
を返しますが、Method
(またはUnboundMethod
)は返しません。 [注:Rubiniusでは、def
はメソッドのコンパイル済みバイトコードを返しますが、それでもMethod
オブジェクトは返しません。]
Ruby言語仕様(5ページと6ページの29-34行目と1-5行目)のセクション6.1の4番目と5番目の段落を見ると、次のことがはっきりとわかります。メソッドとオブジェクトの違い。組み込みクラスの仕様を見ると、そこにはMethod
もUnboundMethod
も入っておらず、Object#method
も入っていないことがわかります。IOW :完全に標準に準拠したRubyインタプリタを構築できます。このインタプリタでは、メソッドではありませんオブジェクトです。
さて、OTOHを確実にブロックしますではありませんオブジェクト。ブロックからオブジェクトを構築Proc
する方法はたくさんあり、元のブロックと同じ動作をします(lambda
、proc
、Proc.new
、&
sigil)ですが、ブロック自体はオブジェクトではありません。
このように考えてください。文字列をFile.new
に渡してファイルオブジェクトを作成できますが、それでは文字列がファイルになりません。ブロックをProc.new
に渡してprocオブジェクトを作成することはできますが、それによってブロックがprocになるわけではありません。
Rubyでは、メソッドとブロックは、それ自体、ネイティブまたはファーストクラスのオブジェクトではありません。ただし、オブジェクトで簡単にラップできるため、通常は違いはありません。
しかし、試してみて、その結果を覚えておいてください、
a = Object.method(:new).object_id
b = Object.method(:new).object_id
a == b
=> false
Haskellでは、すべての値(数値、ラムダ、関数を含む)はファーストクラスの値です。言語のあらゆる面で、それらはすべて同等に扱われます。これはRubyには当てはまりませんが、概算できます。
メソッドの戻り値がオブジェクトであり、nilでない場合でも、オブジェクトとメソッドは同じではありません。メソッド、ラムダ、またはprocスコープ内にない限り、オブジェクトはヒープ上に存在し、メソッド自体はスタック上に存在し、静的オブジェクトとクラスオブジェクトがヒープに割り当てられている間、解釈後にアドレスが割り当てられます。 Rubyは、引き続きCを使用して解釈し、VALUE構造体に渡します。
Rubyでは、メソッドはオブジェクトではありません。 Methodクラスがあり、Methodのインスタンスを取得できるため、これは混乱を招きます。これらのインスタンスは、メソッド自体の単なるプロキシです。これらのインスタンスは、いくつかの便利な機能を提供します。それらには、実際のメソッドに接続するいくつかの内部魔法があります(したがって、Method#call
のようなことを行うことができます)が、実際にそのようなものにアクセスすることはできません(AFAIK)。
1.method(:to_s).object_id == 1.method(:to_s).object_id #=> false
これは、1
に2つの#to_s
メソッドがある(ない)か、メソッド#method
によって返されるものが実際にはメソッド自体ではなく、メソッドのプロキシであることを意味します。メソッドが実際にオブジェクトである場合、同じインスタンスを2回取得できる状況が発生します。メソッドがオブジェクトの場合、メソッドにインスタンス変数を設定するなどの操作を実行できます。後で、メソッドオブジェクトを2回取得した後、そのインスタンス変数の値を取得します。あなたはそれをすることはできません。ですから、一般的に違いはないかもしれませんが、やりたいことができない場合があります。
1.method(:to_s).instance_variable_set(:@foo, 'foo') #=> "foo"
1.method(:to_s).instance_variable_get(:@foo) #=> nil
# And just in case you question it...
1.object_id == 1.object_id #=> true
Rubyでは括弧はオプションであるため、メソッドオブジェクトは通常、method
メソッドを介してメソッドオブジェクトを明示的にフェッチする必要があるという意味で「非表示」になっています。ただし、メソッドオブジェクトをキャプチャしようとすると、オブジェクトのように機能することが非常に明確になります。 Ruby> = 2.1なので、これはこれまで以上に簡単に利用できます。
たとえば、次のように、メソッドをJavascriptの場合と同じように動作させることができます(親はメソッドオブジェクトではなく、親はメソッドの呼び出しに使用されます)。
foo = method def foo
def a(num)
3 * num.to_i
end
n = yield if block_given?
a(n || 3)
rescue
"oops!"
end
def foo.bar(num)
a(num)
end
foo.class #=> Method
foo() #=> 9
foo.call #=> 9
foo.call{2} #=> 6
foo(){2} #=> 6
foo.call{ raise "blam!" } #=> "oops!"
foo.bar(5) #=> 15
この要点を参照 これらの例がテストとして記述されたバージョンについては。
JRLの答え メソッドはオブジェクトではない文字列などのようにオブジェクトではないが、メソッドオブジェクトは本物であり、その他parens/no-parensのものよりも、他のRubyオブジェクトとほとんど同じように動作します。これは ダックタイピング言語 なので、メソッドは次のように修飾されます。私の本の中のオブジェクト。