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”#
仅根据方法的名称,我希望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的实例变量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在类中添加该方法,因此所有实例都将具有该方法。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