6
Foo = Class.new
Foo.instance_eval do
  def instance_bar
    "instance_bar"
  end
end
puts Foo.instance_bar       #=> "instance_bar"
puts Foo.new.instance_bar   #=> undefined method ‘instance_bar’

私の理解では、オブジェクトでinstance_evalを呼び出すと、そのオブジェクトのインスタンス変数またはメソッドを定義できるようになるはずです。

しかし、上記の例では、クラス Foo で呼び出して instance_bar メソッドを定義すると、 instance_barは「Foo.instance_bar」で呼び出すことができるクラス メソッドになります。Foo.new.instance_bar の結果が「undefined method 'instance_bar'」になるため、このコードがインスタンス メソッドを作成していないことは明らかです。

このコンテキストで instance_eval がインスタンス メソッドではなくクラス メソッドを定義するのはなぜですか?

4

2 に答える 2

10

x.instance_evalコンテキストを変更するため、selfに評価されxます。

これにより、インスタンス変数やインスタンス メソッドを定義するなど、多くのことが可能になりますが、x に対してのみです。

 x = Object.new
 y = Object.new

 # define instance variables for x and y
 x.instance_eval { @var = 1 }
 y.instance_eval { @var = 2 }

 # define an instance method for all Objects
 class Object
   def var
     @var
   end
 end

 x.var #=> 1
 y.var #=> 2

Ruby では、いくつかの場所でオブジェクトのインスタンス メソッドを定義できます。通常、それらはクラスで定義され、それらのインスタンス メソッドはそのクラスのすべてのインスタンス間で共有されます (def var上記のように)。

ただし、単一のオブジェクトに対してインスタンス メソッドを定義することもできます。

# here's one way to do it
def x.foo
  "foo!"
end
# here's another
x.instance_eval do
  # remember, in here self is x, so bar is attached to x.
  def bar
    "bar!"
  end
end

xとは同じクラスを持っていますyが、 に対してのみ定義されているため、これらのメソッドを共有していませんx

x.foo #=> "foo!"
x.bar #=> "bar!"
y.foo #=> raises NoMethodError
y.bar #=> raises NoMethodError

Ruby では、クラスでさえも、すべてがオブジェクトです。クラス メソッドは、そのクラス オブジェクトの単なるインスタンス メソッドです。

# we have two ways of creating a class:
class A 
end
# the former is just syntatic sugar for the latter
B = Class.new

# we have do ways of defining class methods:

# the first two are the same as for any other object
def A.baz
  "baz!"
end
A.instance_eval do
   def frog
     "frog!"
   end
end

# the others are in the class context, which is slightly different
class A
  def self.marco
    "polo!"
  end
  # since A == self in here, this is the same as the last one.
  def A.red_light
    "green light!"
  end

  # unlike instance_eval, class context is special in that methods that
  # aren't attached to a specific object are taken as instance methods for instances
  # of the class
  def example
     "I'm an instance of A, not A itself"
  end
end
# class_eval opens up the class context in the same way
A.class_eval do
  def self.telegram
    "not a land shark"
  end
end

繰り返しますが、これらのメソッドはすべてA固有のものでBあり、それらのいずれにもアクセスできないことに注意してください。

A.baz #=> "baz!"
B.telegram #=> raises NoMethodError

ここで重要なことは、クラス メソッドはクラスのオブジェクトの単なるインスタンス メソッドであるということです。Class

于 2009-05-23T03:00:32.113 に答える
2

「instance_eval」の目的はオブジェクトを拡張することですが、「class_eval」の目的はクラスを拡張することです。また、クラスはオブジェクトでもあるため、クラスに instance_eval を適用できます。

クラスの拡張は、従来の OOP の方が理解しやすいと思います。動的言語を使用すると、特定のオブジェクトの動作を簡単に指定できます。各オブジェクトが独自の動作を持つことができるという事実により、アプリケーションの設計に多くの柔軟性が追加されます。同じクラスのオブジェクトでデータが異なるだけではありません。2 人の人間が異なるのは、生まれた年が異なるだけでなく、両親が異なるだけでなく、考え方が異なり、行動も異なるからです。

各オブジェクトの動作を変更できることが基本です。それは多くの言語に存在します。

instance_eval について考えるときは、まずオブジェクトについて考えてください。次に、クラスもオブジェクトであることに気付くでしょう。つまり、新しいオブジェクトを作成し、共通の動作 (メソッド) の記述を保持するという追加の目的を持つオブジェクトです。クラスの定義を使用できるだけでなく、クラスを変数に割り当てたり、クラスを引数として渡したり、クラスのメソッドを呼び出したり、クラスをプログラムしたりすることもできます!

Yehuda Katz と Yugui によって書かれた記事をお勧めします。

于 2014-04-29T07:36:09.267 に答える