我正在学习符号,当我将其作为文件的第一行转储时,我惊讶地发现文件中的所有符号都包含在Symbol.all_symbols
数组中。
但是,如果我尝试访问进一步定义的类,我会得到NameError
,换句话说,它是一个无法识别的符号。
puts "DefinedAtEnd is in symbol list: \
#{Symbol.all_symbols.select {|s| s =~ /^DefinedAtEnd/} != nil} "
puts "do_it is in symbol list: \
#{Symbol.all_symbols.select {|s| s =~ /^do_it/} != nil} "
puts "foo is in symbol list: #{Symbol.all_symbols.select {|s| s =~ /^foo/} != nil} "
#d = DefinedAtEnd.new # This will get a NameError
class DefinedAtEnd
def do_it
foo = 'bar'
puts 'In method do_it'
end
end
运行以上结果会得到以下结果:
DefinedAtEnd is in symbol list: true
do_it is in symbol list: true
foo is in symbol list: true
但如果我取消注释行d = DefinedAtEnd.new
,则会收到以下错误:
uninitialized constant DefinedAtEnd (NameError)
似乎解析器(metparser?)在开始“执行”代码行之前解析整个文件一次,但它还没有构建类。也许这是某种“预先通过”?
答案 0 :(得分:1)
逐行解释文件;你不能在代码中引用尚未定义的 - 被读取与初始化不同。
Ruby 1.9.2输出以下内容,这可能会更有启发性:
foo2.rb:7:in `<main>': uninitialized constant Object::DefinedAtEnd (NameError)
答案 1 :(得分:1)
解析源文件和执行代码之间存在差异。它分两个阶段发生。在解析期间,对象的名称(包括类名和理论上可能被分配的所有变量)被固定到符号表中。也就是说,这是一个你可能不应该依赖的实现细节(更是如此,因为你无法用它做任何有用的事情)。
通常,符号是实习字符串,即从不被垃圾收集的字符串,在整个解释器中只存在一次。
"foo".object_id == "foo".object_id # => false
:foo.object_id == :foo.object_id # => true
与字符串不同,符号也不能在适当的位置更改,它们是不可变的。