Ruby 尝试访问表亲类中的模块变量

Fra*_*nce 2 ruby variables module reference

在这样的脚本中,如何从 Klass 引用 x?

module FatherofKlass

  module Uncle
   x = "my variable's string"
  end

  module Aunt
  end

  class Klass
   puts x
  end

end
Run Code Online (Sandbox Code Playgroud)

我不知道什么样的组合::@@可以使用,等我。理想情况下,我可以使用一个attr函数,但除了使用常量之外,我尝试过的任何方法都没有奏效。

Way*_*rad 5

您无法xUncle的定义之外访问——不是您定义它的方式。没关系,因为只需稍作改动,您就可以做到。

为什么它不能那样工作?

定义叔叔时会发生什么

要了解您的代码为何不起作用,您需要了解一些关于变量作用域以及 Ruby 如何加载代码的知识。当 Ruby 加载包含模块定义的代码时,它会逐行执行。让我们看看Uncle定义模块时会发生什么。

  module Uncle
Run Code Online (Sandbox Code Playgroud)

Ruby 定义模块Uncle并设置selfUncle. 此外,这是重要的部分,Ruby 创建了一个新的作用域。作用域是存储局部变量的地方。

   x = “my variable’s string”
Run Code Online (Sandbox Code Playgroud)

Ruby 定义了局部变量 x并将其设置为"my variable's string". 由于x是局部变量,所以属于当前作用域,即module Uncle声明创建的作用域。

  end
Run Code Online (Sandbox Code Playgroud)

这是您的代码出现问题的地方。将end在模块声明的最后销毁包含可变范围x,使其无法到达x

定义 Klass 时会发生什么。

  class Klass
Run Code Online (Sandbox Code Playgroud)

Klass已创建并self设置为Klass. 然后创建一个新的作用域。

   puts x
Run Code Online (Sandbox Code Playgroud)

我们尝试访问x 当前范围内的变量。由于此范围属于 的定义Klass,因此它只能访问在该定义中定义的局部变量。它无法进入Uncle的作用域,即使可以,那也无所谓:Uncle的作用域早已不复存在,它也x随之消失了。

  end
Run Code Online (Sandbox Code Playgroud)

用常数修复它。

如果x不需要更改,则可以将其定义为常量:

  module Uncle
    X = “my variable’s string”
  end

  class Klass
    puts Uncle::X
  end
Run Code Online (Sandbox Code Playgroud)

通过X以全大写命名,Ruby 创建了一个绑定到 module 的常量Uncle。该常量可以在FatherofKlassas Uncle::X(在 之外FatherofKlass,您将使用FatherofKlass::Uncle::X)中的任何地方引用。

顺便说一句,您puts在定义 Klass时执行。如果你希望它稍后执行,那么把它放在一个方法中:

class Klass
  define print_x
    puts Uncle::X
  end
end
Run Code Online (Sandbox Code Playgroud)

将像这样调用:

k = Klass.new
k.print_x
Run Code Online (Sandbox Code Playgroud)

使用类实例变量修复它。

如果x需要更改,则将其设为常量是行不通的。相反,您可以将其设为类实例变量:

module Uncle
  @x = 1
  class << self
    attr_accessor :x
  end
end

class Klass
  puts Uncle.x    # => 1
  Uncle.x = 2
  puts Uncle.x    # => 2
end
Run Code Online (Sandbox Code Playgroud)

当 Ruby 定义一个用 定义的变量时@,它会将它绑定到self. 因为selfFoo,它创建类实例变量@x。此类实例变量绑定到 module Uncle,因此在 Uncle 定义完成后仍然存在。

不要担心我们已经定义了一个绑定到模块实例变量。类和模块在 Ruby 中密切相关。

定义访问器以x创建允许x读取和写入的方法。因为访问器通常访问实例变量,我们需要将它嵌套class << self在其中以便在类实例变量上定义访问器。