0

我正在学习符号,当我将文件中的所有符号作为文件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?)在开始“执行”代码行之前对整个文件进行了一次解析,但它还没有构建类。也许这是某种“预通行证”?

4

2 回答 2

1

该文件被逐行解释;您不能在尚未定义的代码中引用某些内容——读取与初始化不同。

Ruby 1.9.2 输出以下内容,这可能更具启发性:

foo2.rb:7:in `<main>': uninitialized constant Object::DefinedAtEnd (NameError)
于 2012-06-01T18:34:57.323 回答
1

解析源文件和执行其代码是有区别的。它分两个阶段发生。在解析过程中,对象的名称(包括类名和理论上可能分配的所有变量)被嵌入到符号表中。也就是说,这是一个你可能不应该依赖的实现细节(更是如此,因为你不能真正用它做任何有用的事情)。

通常,符号是内部字符串,即永远不会被垃圾收集并且在整个解释器中只存在一次的字符串。

"foo".object_id == "foo".object_id   # => false
:foo.object_id == :foo.object_id     # => true

与字符串不同,符号也不能原地更改,它们是不可变的。

于 2012-06-01T20:42:16.753 回答