Ruby 如何理解类和实例之间的区别? Foo=Class.new Foo.class\u eval do def级_巴 “类酒吧” 结束 结束 Foo.instance_eval do def实例_条 “实例_栏” 结束 结束 Foo.class_-bar#=>Foo:class的未定义方法“class_-bar” Foo.new.class#bar#=>“class#bar” Foo.instance_-bar#=>“instance_-bar” Foo.new.instance_-bar#=>的未定义方法“instance_-bar”#

Ruby 如何理解类和实例之间的区别? Foo=Class.new Foo.class\u eval do def级_巴 “类酒吧” 结束 结束 Foo.instance_eval do def实例_条 “实例_栏” 结束 结束 Foo.class_-bar#=>Foo:class的未定义方法“class_-bar” Foo.new.class#bar#=>“class#bar” Foo.instance_-bar#=>“instance_-bar” Foo.new.instance_-bar#=>的未定义方法“instance_-bar”#,ruby,class-method,instance-method,Ruby,Class Method,Instance Method,仅根据方法的名称,我希望class_eval允许您向Foo添加class方法,instance_eval允许您向Foo添加实例方法。但他们似乎做了相反的事 在上面的示例中,如果在Foo类上调用class_bar,则会出现未定义的方法错误;如果在Foo.new返回的实例上调用instance_bar,则也会出现未定义的方法错误。这两个错误似乎与类和实例的直观理解相矛盾 这些方法之间的真正区别是什么? 文件: mod.class_eval(字符串[,文件名[,, lineno]])=>obj 计算中

仅根据方法的名称,我希望class_eval允许您向Foo添加class方法,instance_eval允许您向Foo添加实例方法。但他们似乎做了相反的事

在上面的示例中,如果在Foo类上调用class_bar,则会出现未定义的方法错误;如果在Foo.new返回的实例上调用instance_bar,则也会出现未定义的方法错误。这两个错误似乎与类和实例的直观理解相矛盾

这些方法之间的真正区别是什么?

文件:

mod.class_eval(字符串[,文件名[,, lineno]])=>obj

计算中的字符串或块 mod的上下文。这可以用来 向类添加方法

文件:

obj.instance_eval{| | block}=>obj

计算包含Ruby的字符串 源代码或给定的块, 在接收者的上下文中 (obj)。为了设置上下文, 变量self设置为obj,而 代码正在执行,给出了代码 访问obj的实例变量


我想你弄错了。class_eval在类中添加该方法,因此所有实例都将具有该方法。instance_eval将只将该方法添加到一个特定对象

Foo = Class.new
Foo.class_eval do
  def class_bar
    "class_bar"
  end
end
Foo.instance_eval do
  def instance_bar
    "instance_bar"
  end
end
Foo.class_bar       #=> undefined method ‘class_bar’ for Foo:Class
Foo.new.class_bar   #=> "class_bar"
Foo.instance_bar       #=> "instance_bar"
Foo.new.instance_bar   #=> undefined method ‘instance_bar’ for #<Foo:0x7dce8>

instance_eval有效地为所讨论的对象实例创建了一个单例方法。类将在给定类的上下文中创建一个普通方法,该方法可用于该类的所有对象


这里有一个关于和(非特定于ruby的)

的链接,如文档所述,
class\u eval
在模块或类的上下文中计算字符串或块。因此,以下代码是等效的:

foo = Foo.new
foo.instance_eval do
  def instance_bar
    "instance_bar"
  end
end

foo.instance_bar      #=> "instance_bar"
baz = Foo.new
baz.instance_bar      #=> undefined method
在每种情况下,都会重新打开String类并定义一个新方法。该方法可用于该类的所有实例,因此:

class String
  def lowercase
    self.downcase
  end
end

String.class_eval do
  def lowercase
    self.downcase
  end
end
class\u eval
比简单地重新打开类有许多优点。首先,您可以轻松地在变量上调用它,并且很清楚您的意图是什么。另一个优点是,如果类不存在,它将失败。因此,下面的示例将失败,因为
数组
拼写错误。如果简单地重新打开该类,它将成功(并且将定义一个新的不正确的
Aray
类):

最后,
class\u eval
可以接受一个字符串,如果您正在做一些更邪恶的事情,它可能会很有用


instance\u eval
另一方面,根据单个对象实例计算代码:

Aray.class_eval do
  include MyAmazingArrayExtensions
end
因此,对于
instance\u eval
,该方法仅为字符串的单个实例定义

那么为什么
instance\u eval
Class
定义类方法呢

正如
“这很让人困惑”
“查理巴士上的史密斯家”
都是
字符串
实例、
数组
字符串
哈希
以及所有其他类本身都是
的实例。您可以通过对它们调用
#class
来检查这一点:

confusing = "This Is Confusing"
confusing.instance_eval do
  def lowercase
    self.downcase
  end
end   

confusing.lowercase
=> "this is confusing"
"The Smiths on Charlie's Bus".lowercase
NoMethodError: undefined method ‘lowercase’ for "The Smiths on Charlie's Bus":String

因此,当我们调用
instance\u eval
时,它对类的作用与对任何其他对象的作用相同。如果我们使用
instance\u eval
在类上定义一个方法,它将仅为该类的实例定义一个方法,而不是为所有类定义一个方法。我们可以将该方法称为类方法,但它只是该特定类的实例方法。

另一个答案是正确的,但请允许我深入一点

Ruby有许多不同的作用域;据报道,尽管似乎缺乏详细的正式文件,但仍有六份。毫不奇怪,这个问题涉及的范围是实例

当前实例范围由
self
的值定义。所有非限定方法调用都被分派到当前实例,对实例变量的任何引用(看起来像
@this
)也是如此

但是,
def
不是方法调用。
def
创建的方法的目标是当前类(或模块),可以通过
module.nesting[0]
找到

让我们看看两种不同的eval风格如何影响这些范围:


String.class_eval{[self,Module.nesting[0]]}
=>[字符串,字符串]
String.instance_eval{[self,Module.nesting[0]]}
=>[字符串,#]

在这两种情况下,实例范围都是调用*\u eval的对象

对于
class\u eval
,类作用域也成为目标对象,因此
def
为该类/模块创建实例方法

对于
instance\u eval
,类作用域成为目标对象的单例类(又称元类、特征类)。在对象的singleton类上创建的实例方法将成为该对象的singleton方法。类或模块的单例方法通常被称为类方法


类作用域还用于解析常量。类变量(
@@this@@things
)是用类作用域解析的,但在搜索模块嵌套链时,它们跳过了单例类。我发现在单例类中访问类变量的唯一方法是使用
class\u variable\u get/set
instance\u eval
class\u eval
执行一段代码。那你会怎么说?Th
confusing = "This Is Confusing"
confusing.instance_eval do
  def lowercase
    self.downcase
  end
end   

confusing.lowercase
=> "this is confusing"
"The Smiths on Charlie's Bus".lowercase
NoMethodError: undefined method ‘lowercase’ for "The Smiths on Charlie's Bus":String
"This Is Confusing".class
=> String

String.class
=> Class
class A
end

A.instance_eval do
  # self refers to the A class object
  self
end

a = A.new

a.instance_eval do
  # self refers to the a instance object
  self
end
class A
  def initialzie
    @a = “a”
  end

  private

  def private_a
    puts “private a”
  end
end

a = A.new
puts a.instance_eval {  @a }
# => “a”
puts a.instance_eval {  private_a }
# => “private a”
class A
end

A.instance_eval do
  def a_method
    puts “a method”
  end
end

A.a_method
# =>  a method
 a.instance_eval do
  def a_method
    puts "a method"
  end
end

a.a_method
# => a method
class A
end

A.class_eval do
  # self is A
  self
end