我有以下代码,可以动态创建实例变量。如果实例变量不存在,我将使用no方法错误来动态创建attr_reader
和attr_writer
方法。一切正常,但是我不明白为什么在创建第一个@anything
之后看不到attr_reader
实例变量。
require "pry-byebug"
class UberHash
attr_accessor :color
def initialize
@color = nil
end
def method_missing(m, *args, &block)
if m.match(/=/)
puts "create attr writer"
self.instance_variable_set("@#{m[0..-2]}", args[0])
else
puts "create attr reader"
self.instance_variable_get("@#{m}")
end
end
end
uber_hash = UberHash.new
puts "call 1 .................."
p "uber_hash.anything: #{uber_hash.anything}"
p "uber_hash.inspect: #{uber_hash.inspect}"
p uber_hash.anything = "hola"
p uber_hash.inspect
具有以下结果:
call 1 ..................
create attr reader
"uber_hash.anything: "
"uber_hash.inspect: #<UberHash:0x00007f851b1e41a8 @color=nil>"
"#<UberHash:0x00007f851b1e41a8 @color=nil>"
create attr writer
"hola"
"#<UberHash:0x00007f851b1e41a8 @color=nil, @anything=\"hola\">"
在使用方法instnace_variable_set创建了第一个实例变量anything
之后,我知道我创建了attr_reader吗?
如果检查实例,为什么看不到@anything
实例变量?
答案 0 :(得分:0)
您不会在第一次检查中看到实例变量。您希望它在那里,因为在上一行中您叫uber_hash.anything
,对吧?
好吧,uber_hash.anything
调用在else
条件中计算#method_missing
:self.instance_variable_get("@#{m}")
-这就是为什么未设置实例变量的原因。
此外,在#method_missing
条件中,您将打印两条消息:puts "create attr writer"
和puts "create attr reader"
-这是错误的。应该是:puts "create instance variable"
和puts "read instance variable"
答案 1 :(得分:0)
使用方法
instnace_variable_set
创建第一个实例变量后,我知道我创建了attr_reader吗?
不,那是不正确的。您的课程永远不会创建(或运行)attr_reader
。尝试执行此操作(在运行示例命令之后)
p( uber_hash.methods - Object.new.methods )
,您只会看到在类中另外定义的方法是类中的[:color, :color=, :method_missing]
。
由于:color
定义了方法attr_accessor :color
。请记住,attr_accessor
等只是定义方法的捷径。
相比之下,方法:anything
是未定义的,因为您的类从未定义过该方法。
相反,在您的类中,每次调用方法uber_hash.anything
时,uber_hash.method_missing
都会运行并完成工作,即操作或查看实例变量@anything
。
第二,虽然instance_variable_set
确实为实例变量设置了一个值(如果不存在则创建它),instance_variable_get
仅在它存在时引用它,否则返回nil并执行不创建一个实例变量。这就是为什么@anything
是在instance_variable_set
之后而不是仅在instance_variable_get
之后创建的原因。尝试此操作以查看要点(在定义类之后)。
class UberHash
def test_pr
print 'color='; p instance_variable_get("@color")
print 'other='; p instance_variable_get("@other")
p instance_variables # => @other is not defined
print 'other='; p instance_variable_set("@other", 99)
p instance_variables # => @other is NOW defined
end
end
uber_hash.test_pr
因此,您看到的行为是完全合法的。
注意:this past answer对此进行了说明。