class Observer
def initialize(&block)
instance_eval(&block) if block_given?
end
end
我想知道在这里假设与'initialize'一起使用的块的类型。
由于调用了instance_eval,这意味着在Observer类的上下文中计算了块。
为什么会这样做,而不是比如说class_eval,以及在类的上下文中评估块的结果可能是什么?
另外,如何调用它?
答案 0 :(得分:9)
首先,你不能做这样的事情:
class Observer
def initialize(&block)
class_eval(&block) if block_given?
end
end
因为没有为class_eval
的实例定义Observer
。它在Module
中定义(Class
下降)。我们稍后会回到class_eval
。
使用上述习语的原因通常是允许块初始化:
x = Observer.new do
add_event(foo)
some_other_instance_method_on_observer
self.some_attribute = something
end
另外,您可以将方法添加到类的给定实例中:
foo = Observer.new do
def foo
'foo'
end
end
foo.foo # => "foo"
如果没有instance_eval
,你可以完成同样的事情:
class Foo
def initialize
yield self if block_given?
end
end
foo = Foo.new do |x|
x.add_event(foo)
x.some_other_instance_method_on_observer
x.self.some_attribute = something
end
但这并没有让你能够添加方法。如果你这样做:
foo = Foo.new do
def foo
'foo'
end
end
foo.foo # => "foo"
似乎有效,对吧?但是你实际做的是将foo
方法添加到所有内容中,因为self
设置为“主”对象。它等同于简单地定义块外的方法。它们作为实例方法添加到Object
,因此它们可以处理所有事情。
现在,正如所承诺的那样,回到class_eval
。你可以做这样的事情:
class Observer
def initialize(&block)
class.class_eval(&block) if block_given?
end
end
然后你打开整个班级:
x = Observer.new { def foo; 'foo'; end }
x.foo # => "foo"
y = Observer.new
y.foo # => "foo"
这通常不是我们想要做的。另外,self
将是类,而不是实例。这使得它对于块初始化毫无用处,如上所示。
答案 1 :(得分:2)
一个用例是在其上下文中设置观察者的状态。
也许
o = Observer.new do
listen_to(<some object>)
report_to(<something>)
end
这样的使用不适用于class_eval,它只能访问类状态
答案 2 :(得分:0)
Initialize是一个实例方法。它是在实例的上下文中执行的,而不是类本身。因此instance_eval
导致块也在实例的上下文中执行。
普通对象实例中没有class_eval
这样的东西 - 它只是为类定义的。
答案 3 :(得分:0)
只是因为 initialize 方法是一个实例方法, class_eval 是为类类型的对象定义的,这意味着它们只能在类方法或类体内部。
因此,以下代码段会引发错误:
“”。class_eval {methods}#=&gt; NoMethodError:未定义的方法 `class_eval'代表“”:String
虽然这个会奏效:
s.class.class_eval{methods} #=> ["methods", "respond_to?", "module_eval", "class_variables", "dup", "instance_variables", "protected_instance_methods", "__id__", "public_method_defined?", "eql?", "object_id", "const_set", "id", "singleton_methods", "send", "class_eval", "taint", "include?", "private_instance_methods", "frozen?", "instance_variable_get", "private_method_defined?", "__send__", "instance_of?", "name", "to_a", "autoload", "type", "new", "protected_methods", "instance_eval", "display", "instance_method", "instance_variable_set", "kind_of?", "protected_method_defined?", "extend", "const_defined?", "to_s", "ancestors", "public_class_method", "allocate", "class", "<=>", "hash", "<", "tainted?", "private_methods", "==", "instance_methods", "===", "class_variable_defined?", ">", "nil?", "untaint", "constants", ">=", "is_a?", "autoload?", "<=", "inspect", "private_class_method", "const_missing", "method", "clone", "=~", "public_instance_methods", "public_methods", "method_defined?", "superclass", "instance_variable_defined?", "equal?", "freeze", "included_modules", "const_get"]