为什么创建后看不到实例变量? (读者阅读器)

时间:2018-10-09 15:10:41

标签: ruby

我有以下代码,可以动态创建实例变量。如果实例变量不存在,我将使用no方法错误来动态创建attr_readerattr_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实例变量?

2 个答案:

答案 0 :(得分:0)

您不会在第一次检查中看到实例变量。您希望它在那里,因为在上一行中您叫uber_hash.anything,对吧?

好吧,uber_hash.anything调用在else条件中计算#method_missingself.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对此进行了说明。