Ruby模块变量访问器未按预期工作

Ruby模块变量访问器未按预期工作,ruby,Ruby,所以我想要一个带有变量和访问方法的模块。 我的代码看起来像这样 module Certificates module Defaults class << self attr_accessor :address def get_defaults address = "something" make_root_cert end def make_root_cert blub = address

所以我想要一个带有变量和访问方法的模块。
我的代码看起来像这样

module Certificates
  module Defaults

  class << self
    attr_accessor :address

    def get_defaults
      address = "something"
      make_root_cert
    end

    def make_root_cert
      blub = address
      # do somthing
    end
  end
end
模块证书
模块默认值

类在您的
get\u defaults
方法中,
address
是一个局部变量。要使用setter,必须键入以下内容:

self.address = "something"

这将正确地调用
address=
方法。

由于Ruby解释器将局部变量定义置于比方法调用更高的优先级,因此会出现这种相当混乱的行为。这里有一致性,但除非你事先知道它是如何工作的,否则很难看清楚

考虑到Ruby中有很多东西都是对象和方法调用,所以很自然地会假设变量定义是某个对象上调用的某种方法(比如内核或main或定义它的对象或其他对象),并且生成的变量是某种对象。如果是这种情况,您可能会猜测解释器将根据方法查找规则解决变量定义和其他方法之间的名称冲突,并且仅在没有首先找到与潜在变量定义同名的方法时才定义新变量

但是,变量定义不是方法调用,变量也不是对象。相反,变量只是对对象的引用,而变量定义是解释器在语言表面下跟踪的内容。这就是为什么
Kernel.local_variables
返回一个符号数组,而无法获得某种局部变量对象的数组

因此,Ruby需要一组特殊的规则来处理变量和方法之间的名称冲突。非局部变量有一个特殊的前缀,表示它们的作用域($,@,等等),它解决了这个问题,但局部变量却不是这样。如果Ruby在方法之后需要parens,那么这也可以解决这个问题,但是我们有幸不必这样做。为了方便地引用不带前缀的局部变量和调用不带paren的方法,该语言默认假定只要局部变量在作用域中就需要它。它本来可以用另一种方式设计,但是你会遇到一些奇怪的情况,你定义了一个局部变量,它在程序的中途被一个同名的遥远的方法瞬间掩盖了,所以这样可能更好

,p。88,有这样一句话:

“…局部变量没有标点符号作为前缀。这意味着局部变量引用看起来就像方法调用表达式。如果Ruby解释器 已看到对局部变量的赋值,它知道它是变量而不是方法,并且它可以返回变量的值。如果没有赋值,则Ruby将表达式视为方法调用。如果不存在同名的方法,Ruby将引发一个
NameError

它接着解释了为什么在
make\u root\u cert
中调用
address
时会得到
nil

因此,一般来说,在初始化局部变量之前尝试使用它会导致错误。有一个怪癖——当Ruby解释器看到变量的赋值表达式时,变量就存在了。即使未实际执行该分配,情况也是如此。存在但尚未赋值的变量将被赋予默认值
nil
。例如:

   a = 0.0 if false # This assignment is never executed
   print a          # Prints nil: the variable exists but is not assigned
   print b          # NameError: no variable or method named b exists"
使用
attr\u accessor
获得的setter方法会导致解释器在调用setter方法之前创建一个变量,但必须调用该方法才能为该变量赋值,而不是
nil
address=“something”
get\u defaults
中定义一个名为
address
的方法中的局部变量,该变量在方法末尾超出范围。当您调用
make\u root\u cert
时,没有名为
address
的局部变量,因此调用了使用
attr\u accessor
获得的getter方法
address
,并返回
nil
,因为没有调用setter方法来为其提供其他值
self.address=
让解释器知道您想要类方法
address=
而不是一个新的局部变量,从而解决歧义