Ruby 试图访问堂兄中的模块变量 class

Ruby Trying to access module variables within cousin class

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

module FatherofKlass

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

  module Aunt
  end

  class Klass
   puts x
  end

end

我不确定我可以使用 ::@@ 等的哪种组合。理想情况下,我可以使用 attr 函数,但除了使用常量外,我尝试过的任何方法都不起作用。

试试这个:

module FatherofKlass
  module Uncle
   X = "my variable's string"
  end

  module Aunt
  end

  class Klass
   puts FatherofKlass::Uncle::X
  end
end
# my variable's string

您不能从 Uncle 的定义之外访问 x -- 不是您定义它的方式。没关系,因为一个小的改变,你可以做到。

为什么不是这样?

定义 Uncle 时会发生什么

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

  module Uncle

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

   x = “my variable’s string”

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

  end

这就是您的代码出错的地方。模块声明末尾的 end 破坏了包含变量 x 的范围,使得无法到达 x.

定义 Klass 时会发生什么。

  class Klass

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

   puts x

我们尝试在当前范围内访问变量x。由于这个作用域属于Klass的定义,它只能访问定义在该定义内的局部变量。它无法进入 Uncle 的范围,即使可以,也没关系:Uncle 的范围早就消失了,它的 x 也随之消失了。

  end

正在用常量修复它。

如果x不需要改变,那么可以定义为常量:

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

  class Klass
    puts Uncle::X
  end

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

顺便说一下,您的 puts 将在定义 Klass 时执行 。如果你想让它稍后执行,那么把它放在一个方法里面:

class Klass
  define print_x
    puts Uncle::X
  end
end

会像这样调用:

k = Klass.new
k.print_x

用 class 实例变量修复它。

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

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

当 Ruby 定义一个用 @ 定义的变量时,它将它绑定到 self。由于 selfFoo,它创建 class 实例变量 @x。这个 class 实例变量绑定到模块 Uncle,因此在 Uncle 完成定义后仍然存在。

不要担心我们已经定义了一个 class 实例变量绑定到 模块 。 类 和模块在 Ruby.

中密切相关

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