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
。由于 self
是 Foo
,它创建 class 实例变量 @x
。这个 class 实例变量绑定到模块 Uncle
,因此在 Uncle 完成定义后仍然存在。
不要担心我们已经定义了一个 class 实例变量绑定到 模块 。 类 和模块在 Ruby.
中密切相关
定义 x
的访问器创建允许读取和写入 x
的方法。因为访问器通常访问 实例变量 ,我们需要将其嵌套在 class << self
中,以便在 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
。由于 self
是 Foo
,它创建 class 实例变量 @x
。这个 class 实例变量绑定到模块 Uncle
,因此在 Uncle 完成定义后仍然存在。
不要担心我们已经定义了一个 class 实例变量绑定到 模块 。 类 和模块在 Ruby.
中密切相关定义 x
的访问器创建允许读取和写入 x
的方法。因为访问器通常访问 实例变量 ,我们需要将其嵌套在 class << self
中,以便在 class 实例变量 .