为什么在类上调用 instance_eval() 时要定义类方法?

发布于 2024-07-21 19:47:26 字数 662 浏览 2 评论 0原文

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<对象上的 /a> 应该允许您为该对象定义实例变量或方法。

但在上面的示例中,当您在类 Foo 上调用它来定义 instance_bar 方法时,instance_bar 就变成了一个可以通过“Foo.instance_bar”调用的类方法。 很明显,这段代码没有创建实例方法,因为 Foo.new.instance_bar 导致“未定义的方法'instance_bar'”。

为什么instance_eval在此上下文中定义类方法而不是实例方法?

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’

My understanding is that calling instance_eval on an object is supposed to allow you to define an instance variable or method for that object.

But in the example above, when you call it on class Foo to define the instance_bar method, instance_bar becomes a class method that can be invoked with "Foo.instance_bar". It is clear that this code has not created an instance method because Foo.new.instance_bar results in "undefined method ‘instance_bar’".

Why does instance_eval define a class method rather than an instance method in this context?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

韶华倾负 2024-07-28 19:47:26

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

即使xy具有相同的类,它们也不共享这些方法,因为它们是仅为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 的对象的实例方法

x.instance_eval changes your context so self evaluates to x.

This allows you to do many things, including defining instance variables and instance methods but only for 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 lets you define instance methods for an object in a couple places. Normally,
one defines them in a class, and those instance methods are shared among all instances
of that class (like def var above).

However, we can also define an instance method for just a single object:

# 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

Even though x and y have the same class, they don't share these methods, since they were only defined for x.

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

Now in ruby, everything's an object, even classes. Class methods are just instance methods
for that class object.

# 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

Note again, that all these methods are A-specific, B doesn't get access to any of them:

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

The important thing to take away from here is that
class methods are just instance methods of an object of class Class

终止放荡 2024-07-28 19:47:26

“instance_eval”的目的是扩展对象,而“class_eval”的目的是扩展类。 由于类也是对象,因此您可以对类应用instance_eval。

我想类的扩展在经典的 OOP 中更容易理解。 动态语言使我们能够轻松地指定特定对象的行为。 事实上,每个对象都可以有自己的行为,这为应用程序设计增加了很大的灵活性。 对于同一类的对象来说,不仅数据会有所不同。 两个人的不同不仅因为他们出生的年份不同,不仅因为他们有不同的父母,而且他们的想法不同,因此行为也不同。

改变每个对象的行为的能力是基础。 它存在于多种语言中。

考虑instance_eval 首先考虑对象。 然后您将意识到类也是对象 - 对象的附加目的是创建新对象,以保存常见行为(方法)的描述。 您不仅可以使用类的定义,还可以将类分配给变量,将类作为参数传递,调用类上的方法,对类进行编程!

我会推荐 Yehuda Katz 和 Yugui 撰写的文章来深入研究它:

The purpose of 'instance_eval' is to extend objects, but the purpose of 'class_eval' is to extend classes. And because classes are also objects, you can apply instance_eval on classes.

I guess that extending of classes is just more understandable in classic OOP. Dynamic languages allow us to easily specify behaviour of particular objects. Fact that each object can have own behaviour adds a lot of flexibility designing an application. Not only data can vary for objects of the same class. Two humans differ not only because they were born in different years, not only because they have different parents but they can think different and thus behave different.

Ability to change the behaviour of each object is fundamental. It exists in many languages.

Thinking about instance_eval think about objects first. Then you'll realize that classes are also objects - objects which additional purpose to create new objects, to hold description of common behaviour (methods). You can not only use definition of a class, but can also assign class to a variable, pass class as an argument, call method on a class, program a class!

I would recommend articles written by Yehuda Katz and Yugui to dive deeper into it:

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文