Ruby metaprogramming: Initialize singleton_class variable

假如想象 提交于 2020-01-03 17:09:17

问题


  • Why does Foo.val return nil instead of "foo" before calling Foo.set?
  • Is there any mechanism for initializing @val on class evaluation?
  • In which scope is @val = "foo" stored into?

    class Foo
      class << self
        @val  = "foo"
        attr_reader :val
    
        def set(val)
          @val = val
        end
      end
    end
    
    p Foo.val # nil
    Foo.set("bar")
    p Foo.val # "bar"
    

回答1:


You can initialize @val in Foo like this:

class Foo
  @val  = "foo"
  class << self
    attr_reader :val

    def set(val)
      @val = val
    end
  end
end

p Foo.val         #=> "foo"
Foo.set("bar")
p Foo.val         #=> "bar"

Your code initializes @val not on Foo, but on Foo's metaclass




回答2:


Ruby generally executes expressions upon parsing them. The reason why your code did not perform as expected is because you are setting a class instance variable for the singleton class of Foo, but on the other hand you are accessing the class instance variable of Foo itself, that's why it doesn't work:

class << self
  @val  = "foo" # scope is class scope of singleton class of Foo
  attr_reader :val

  def set(val)
    # scope is instance scope of singleton class of Foo (equal to Foo itself)
    @val = val 
  end
end

That's why Foo.val yields nil in your case - it hasn't been set yet.

Setting val on class evaluation can be achieved in the way that Victor already demonstrated.

See also this post for a discussion about scope.




回答3:


No need to use #set. Simply define #val method and use nil guard:

class Foo
    class << self
        def val; @val ||= "bar" end
    end
end
p Foo.val  #=> "bar"


来源:https://stackoverflow.com/questions/6968333/ruby-metaprogramming-initialize-singleton-class-variable

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!