给出以下Ruby类
class Example
PARENTS = [
FATHER = :father,
MOTHER = :mother
]
end
这些工作符合预期
> Example::PARENTS
#=> [:father, :mother]
> Example::PARENTS[0]
#=> :father
> Example::PARENTS[1]
#=> :mother
但是,为什么这样做有效?
> Example::FATHER
#=> :father
> Example::MOTHER
#=> :mother
实际上,为什么Example类的作用域中有三个常量?
> Example.constants
#=> [:MOTHER, :PARENTS, :FATHER]
要点是,如果我使用其他方法扩展该类:
class Example
def self.whos_your_daddy
FATHER
end
end
它像往常一样访问常量。
> Example.whos_your_daddy
#=> :father
这怎么可能?通过声明数组的常量 inside ,我希望它们在数组内部范围内。请在答案中引用相关文档。
编辑:我想澄清一下,回答这个问题的最简单方法是解释两件事:
首先,执行以下代码会发生什么:
PARENTS = [
FATHER = :father,
MOTHER = :mother
]
第二,是否在任何将常量与要声明的类的范围相关的地方声明了常量?为什么?
答案 0 :(得分:5)
首先,执行以下代码会发生什么:
PARENTS = [ FATHER = :father, MOTHER = :mother ]
PARENTS = ...
尝试设置常数PARENTS
。但是,为此,它必须评估分配的右侧:
[...]
尝试创建一个数组。但是,为了这样做,它必须评估其参数:
FATHER = :father
将常量FATHER
设置为:father
。分配的结果是:father
,它成为第一个参数。MOTHER = :mother
将常量MOTHER
设置为:mother
。分配的结果是:mother
,它成为第二个参数。所以按照时间顺序的顺序:
FATHER
设置为:father
MOTHER
设置为:mother
:father
和:mother
的数组PARENTS
设置为该数组您的代码等同于:
FATHER = :father
MOTHER = :mother
PARENTS = [FATHER, MOTHER] # or [:father, :mother]
通过声明数组内部的常量,我希望它们在数组内部范围内。请在答案中引用相关文档。
您可以使用Module.nesting
来确定当前的嵌套,即在以下位置定义常量:(docs中的更多示例)
class Example
p outer_nesting: Module.nesting
PARENTS = [
p(inner_nesting: Module.nesting)
]
end
输出:
{:outer_nesting=>[Example]}
{:inner_nesting=>[Example]}
如您所见,数组文字不影响当前的嵌套。这两个位置的常量都将在Example
下定义。
如果您真的想在数组内部声明常量(即在数组的singleton类内部),则可以执行以下操作:
class Example
PARENTS = []
class << PARENTS
FATHER = :father
MOTHER = :mother
PARENTS.push(FATHER, MOTHER)
end
end
p Example.constants #=> [:PARENTS]
p Example::PARENTS.singleton_class.constants #=> [:FATHER, :MOTHER]
以上内容仅用于演示目的,没有必要这样做。
答案 1 :(得分:3)
我可以理解它如何造成混淆,但除了不鼓励将值重新分配给常量这一事实之外,就范围而言,实例变量和常量极为相似。
第一个类声明中的视觉技巧是在数组内声明常量的地方。
首先:理解声明常量时,返回的值就是您的定义。例如
FATHER = :father
#=> :father
现在,让我们看一下常量声明:
PARENTS = [
FATHER = :father,
MOTHER = :mother
]
要声明PARENT
,您可以使用:
PARENTS = [
:father,
:mother
]
但是您走得更远,并且在定义中也声明了一个常量。现在,请理解实例变量和常量的范围是相似的,它与在其内声明的实例相关联,因此在任何地方声明一个常量都会将其与实例相关联。 strong>
通过执行FATHER = :father
,您已经声明了另一个常量,并且常量的范围将始终是在其中声明的类,在这种情况下为Example
。 MOTHER = :mother
也是如此。
如果您更习惯于使用实例变量-这样做的原因是相同的:给定以下Ruby类。
class Example
@parents = [
@father = :father,
@mother = :mother
]
end
这些工作符合预期
> Example.instance_variable_get :@parents
#=> [:father, :mother]
> Example.instance_variable_get(:@parents)[0]
#=> :father
> Example.instance_variable_get(:@parents)[1]
#=> :mother
但这也可以。
> Example.instance_variable_get :@father
#=> :father
> Example.instance_variable_get :@mother
#=> :mother
实际上,这三个示例在Example类的范围内。
> Example.instance_variables
#=> [:@mother, :@parents, :@father]
要点是,如果我使用其他方法扩展该类:
class Example
def self.whos_your_daddy
@father
end
end
它像往常一样访问实例变量。
> Example.whos_your_daddy
#=> :father
答案 2 :(得分:2)
我在第94页的ruby编程书中发现了这一点:
在类或模块内定义的常量可以在类或模块内的任何位置进行未经修饰的访问。在类或模块之外,可以使用作用域运算符::来访问它们,该操作符以返回适当的类或模块对象的表达式为前缀。在任何类或模块之外定义的常量可以不加修饰地访问,也可以使用没有前缀的范围运算符来访问。常量不能在方法中定义。可以通过使用类或模块名称以及作用域运算符从常量名称的外部将常量添加到现有的类和模块中。
结论,在一个类中不能有两个具有相同名称的常量,一个在数组内,而另一个在数组外。因此,因为该范围是整个类,所以您不需要该范围来访问它。
在常量数组中不需要常量,因为数组是常量,其内部值也是常量。
答案 3 :(得分:2)
一个简短的答案可能是:
您的代码等同于:
class Example
PARENTS = [
Example.const_set("FATHER", :father),
Example.const_set("MOTHER", :mother)
]
end
经过一些测试:
puts Example.is_a? Module
# true
puts Example.is_a? Class
# true
p Example::PARENTS
# [:father, :mother]
p Example.constants
# [:FATHER, :MOTHER, :PARENTS]
puts Example::PARENTS.is_a? Module
# false
Example::PARENTS.const_set("UNCLE", :uncle)
# undefined method `const_set' for [:father, :mother]:Array (NoMethodError)
*:顶级常量(=在类或模块外部定义的常量)似乎存储在Object
中。
答案 4 :(得分:1)
您的答案就在您的问题中。
class Example
PARENTS = [
FATHER = :father,
MOTHER = :mother
]
end
这里有3个常量(PARENTS
,FATHER
和MOTHER
)。而且它们在一个范围内。数组不会产生新作用域。
Example.constants
方法只是向您显示它们。
即使将方法添加到类中,它也绝对不会改变
class Example
PARENTS = [
FATHER = :father,
MOTHER = :mother
]
def self.whos_your_daddy
FATHER
end
end
Example.constants #=> [:MOTHER, :PARENTS, :FATHER]
答案 5 :(得分:0)
数组定义不是一个块。它不在Array的范围内运行。
与以下内容没有什么不同
PARENTS = []
PARENTS << mom = :mother
如您所见,范围不变:
> puts self
main
=> nil
> array = [ puts(self.inspect) ]
main
=> [nil]
Assignment返回分配的值:
> foo = "bar"
"bar"
> puts foo
bar
> puts(foo = "baz")
baz
> puts foo
baz
您不能在数组中“存储”诸如MOTHER = :mother
之类的东西,因为它不是值,它会返回一个值,即:mother
。