当 attr_accessor 在 class 方法中时会发生什么?
What happens when attr_accessor is within a class method?
所以我想到了这个,想知道当下面的事情完成后会发生什么。
class Test
def self.abc
attr_accessor :John
end
end
object = Test.new
puts "before calling class method abc: #{object.class.instance_methods(false)}"
Test.abc
puts "after calling class method abc: #{object.class.instance_methods(false)}"
这里我检查的是,getter 和 setter 方法是否以这种方式创建。如果是这样,那些实例方法或 class 方法。首先我创建一个新对象,然后查看该对象的实例方法是什么。在下一行之后,我 运行 class
方法 abc
然后再次检查 object
的实例方法。当时只有我能看到John
和John=
这两个方法。这是怎么发生的?为什么 运行 宁 class 方法动态地向已创建的对象添加方法?。谁能给我解释一下。
代码的输出是:
before calling class method abc: []
after calling class method abc: [:John, :John=]
在 class 方法中,self
是 class 本身。因此,以下内容在他们最终所做的事情上是等价的:
class Test
def self.abc
# `self` in this context is Test.
# This sends the message `:attr_accessor, :john` to `Test`
attr_accessor :john
end
end
class Test
# `self` in this context is Test.
# This sends the message `:attr_accessor, :john` to `Test`
attr_accessor :john
end
但是,正如您所指出的,解析 class 时不会执行 Test::abc
,因此不会调用 attr_accessor
,也不会添加实例方法。在 运行 时执行此操作是完全有效的,事实上,这是在 Rails.
中执行的大部分元编程的基础
通常,如果您希望通过 class 方法添加访问器,您可以在定义之后但仍在 class 声明期间调用该 class 方法:
class Test
def self.abc
attr_accessor :john
end
abc
end
这实际上 运行,并在 class!
上正确声明访问器
关于您的问题:
How come a running of a class method dynamically add methods to already created objects?
这是因为实例化 class 不会在实例化时实例化 class 的 "snapshot" - 它会创建一个对象,该对象委托其大部分功能(包括它上的实例方法的发现)到与之关联的 class。请注意,也可以在实例 上定义新方法 ,它不会扩展回 class:
class Test
attr_accessor :foo
end
t1 = Test.new
t2 = Test.new
Test.send(:define_method, :bar) {}
puts t1.respond_to? :foo # => true
puts t2.respond_to? :foo # => true
puts t1.respond_to? :bar # => true
puts t2.respond_to? :bar # => true
t1.define_singleton_method(:baz) {}
puts t1.respond_to? :baz # => true
puts t2.respond_to? :baz # => false
首先,请注意代替
object = Test.new
object.class.instance_methods(false)
你可以简单地写
Test.instance_methods(false)
所以让我们简化一下:
puts "before calling class method abc: #{Test.instance_methods(false)}"
# (prints) []
Test.abc
puts "after calling class method abc: #{Test.instance_methods(false)}"
# (prints) [:John, :John=]
对此行为有一个简短的解释,但也有一个较长的解释。
简短说明
Test.method(:attr_accessor)
#=> #<Method: Class(Module)#attr_accessor>
这个return值,连同
这个事实
Test.class #=> Class
告诉我们 attr_accessor
是 Class
的 instance_method,因此是 Test
的方法。让我们确认一下。
Class.instance_methods.include?(:attr_accessor)
#=> false
糟糕! (你期待 => true
?)。那只能意味着 attr_accessor
是受保护的或私有的实例方法:
Class.protected_instance_methods.include?(:attr_accessor)
#=> false
Class.private_instance_methods.include?(:attr_accessor)
#=> true
因此
Class.private_instance_methods.include?(:attr_accessor)
#=> true
所以attr_accessor
只是Test
的class、Class
的私有实例方法,使其成为Test
的私有方法。表达式(来自之前的)
Test.method(:attr_accessor)
#=> #<Method: Class(Module)#attr_accessor>
也告诉我们attr_accessor
定义在Class
的superclass Module
.
Class.superclass
#=> Module
Class.ancestors
#=> [Class, Module, Object, Kernel, BasicObject]
Class.instance_method(:attr_accessor).owner
#=> Module
Test.method(:attr_accessor).owner
#=> Module
更长的解释
方法 Module#attr_accessor 可以通过以下两种方式之一提供给 class Test
。这就是 Ruby 的 对象模型 的本质。 (我回避了单例 class 方法的位置。)
1. Test从它的superclass
继承方法
Test.superclass
#=> Object
Test.ancestors
#=> [Test, Object, Kernel, BasicObject]
让我们看看。
Object.method(:attr_accessor)
#=> #<Method: Class(Module)#attr_accessor>
Object.public_methods.include?(:attr_accessor)
#=> false
Object.private_methods.include?(:attr_accessor)
#=> true
2。 attr_accessor
是Test
的class
的实例方法
Test.class
#=> Class
Class.private_instance_methods.include?(:attr_accessor)
#=> true
所以Test
既从它的superclass继承了attr_accessor
,又可以作为它的class的一个实例方法。这种二元性通常用 this one.
这样的图表来解释。
Ruby 首先检查 Test
的 class、Class
的实例方法 attr_accessor
。它会在哪里找到它。 (如果她没有在那里找到它,那么她会在 superclass 中寻找方法(不是实例方法)。)
所以我想到了这个,想知道当下面的事情完成后会发生什么。
class Test
def self.abc
attr_accessor :John
end
end
object = Test.new
puts "before calling class method abc: #{object.class.instance_methods(false)}"
Test.abc
puts "after calling class method abc: #{object.class.instance_methods(false)}"
这里我检查的是,getter 和 setter 方法是否以这种方式创建。如果是这样,那些实例方法或 class 方法。首先我创建一个新对象,然后查看该对象的实例方法是什么。在下一行之后,我 运行 class
方法 abc
然后再次检查 object
的实例方法。当时只有我能看到John
和John=
这两个方法。这是怎么发生的?为什么 运行 宁 class 方法动态地向已创建的对象添加方法?。谁能给我解释一下。
代码的输出是:
before calling class method abc: []
after calling class method abc: [:John, :John=]
在 class 方法中,self
是 class 本身。因此,以下内容在他们最终所做的事情上是等价的:
class Test
def self.abc
# `self` in this context is Test.
# This sends the message `:attr_accessor, :john` to `Test`
attr_accessor :john
end
end
class Test
# `self` in this context is Test.
# This sends the message `:attr_accessor, :john` to `Test`
attr_accessor :john
end
但是,正如您所指出的,解析 class 时不会执行 Test::abc
,因此不会调用 attr_accessor
,也不会添加实例方法。在 运行 时执行此操作是完全有效的,事实上,这是在 Rails.
通常,如果您希望通过 class 方法添加访问器,您可以在定义之后但仍在 class 声明期间调用该 class 方法:
class Test
def self.abc
attr_accessor :john
end
abc
end
这实际上 运行,并在 class!
上正确声明访问器关于您的问题:
How come a running of a class method dynamically add methods to already created objects?
这是因为实例化 class 不会在实例化时实例化 class 的 "snapshot" - 它会创建一个对象,该对象委托其大部分功能(包括它上的实例方法的发现)到与之关联的 class。请注意,也可以在实例 上定义新方法 ,它不会扩展回 class:
class Test
attr_accessor :foo
end
t1 = Test.new
t2 = Test.new
Test.send(:define_method, :bar) {}
puts t1.respond_to? :foo # => true
puts t2.respond_to? :foo # => true
puts t1.respond_to? :bar # => true
puts t2.respond_to? :bar # => true
t1.define_singleton_method(:baz) {}
puts t1.respond_to? :baz # => true
puts t2.respond_to? :baz # => false
首先,请注意代替
object = Test.new
object.class.instance_methods(false)
你可以简单地写
Test.instance_methods(false)
所以让我们简化一下:
puts "before calling class method abc: #{Test.instance_methods(false)}"
# (prints) []
Test.abc
puts "after calling class method abc: #{Test.instance_methods(false)}"
# (prints) [:John, :John=]
对此行为有一个简短的解释,但也有一个较长的解释。
简短说明
Test.method(:attr_accessor)
#=> #<Method: Class(Module)#attr_accessor>
这个return值,连同
这个事实Test.class #=> Class
告诉我们 attr_accessor
是 Class
的 instance_method,因此是 Test
的方法。让我们确认一下。
Class.instance_methods.include?(:attr_accessor)
#=> false
糟糕! (你期待 => true
?)。那只能意味着 attr_accessor
是受保护的或私有的实例方法:
Class.protected_instance_methods.include?(:attr_accessor)
#=> false
Class.private_instance_methods.include?(:attr_accessor)
#=> true
因此
Class.private_instance_methods.include?(:attr_accessor)
#=> true
所以attr_accessor
只是Test
的class、Class
的私有实例方法,使其成为Test
的私有方法。表达式(来自之前的)
Test.method(:attr_accessor)
#=> #<Method: Class(Module)#attr_accessor>
也告诉我们attr_accessor
定义在Class
的superclass Module
.
Class.superclass
#=> Module
Class.ancestors
#=> [Class, Module, Object, Kernel, BasicObject]
Class.instance_method(:attr_accessor).owner
#=> Module
Test.method(:attr_accessor).owner
#=> Module
更长的解释
方法 Module#attr_accessor 可以通过以下两种方式之一提供给 class Test
。这就是 Ruby 的 对象模型 的本质。 (我回避了单例 class 方法的位置。)
1. Test从它的superclass
继承方法Test.superclass
#=> Object
Test.ancestors
#=> [Test, Object, Kernel, BasicObject]
让我们看看。
Object.method(:attr_accessor)
#=> #<Method: Class(Module)#attr_accessor>
Object.public_methods.include?(:attr_accessor)
#=> false
Object.private_methods.include?(:attr_accessor)
#=> true
2。 attr_accessor
是Test
的class
Test.class
#=> Class
Class.private_instance_methods.include?(:attr_accessor)
#=> true
所以Test
既从它的superclass继承了attr_accessor
,又可以作为它的class的一个实例方法。这种二元性通常用 this one.
Ruby 首先检查 Test
的 class、Class
的实例方法 attr_accessor
。它会在哪里找到它。 (如果她没有在那里找到它,那么她会在 superclass 中寻找方法(不是实例方法)。)