在about_symbols.rb Ruby Koan(https://github.com/edgecase/ruby_koans)中,我有以下代码:
RubyConstant = "What is the sound of one hand clapping?"
def test_constants_become_symbols
all_symbols = Symbol.all_symbols
assert_equal true, all_symbols.include?(:"nonexistent")
assert_equal true, all_symbols.include?(:"What is the sound of one hand clapping?")
assert_equal true, all_symbols.include?("What is the sound of one hand clapping?".to_sym)
end
原样,测试通过。
三个问题:
为什么第一个断言通过? :"nonexistent"
不应该包含在all_symbols中,但它包括在内,所以我必须误解一些东西。
当我注释掉第二个断言时,测试失败,因为"What is the sound of one hand clapping?".to_sym
未包含在all_symbols中,而:"What is the sound of one hand clapping?"
包括在内。既然它们是等价的,为什么最后一个断言失败了?另外,为什么第二个断言未被注释时它会通过? (为什么第二个断言对第三个断言有影响?)
据我所知,这个Ruby Koan的观点是证明常量成为符号(至少,这是我从方法名称推断的)。由于RubyConstant是一个值为"What is the sound of one hand clapping?"
的常量,为什么"What is the sound of one hand clapping?".to_sym
不包含在符号列表中?我能想到的唯一解释是,与方法名称相反,常量实际上不会成为符号。
感谢您的帮助!
答案 0 :(得分:7)
解释器在解析:nonexistent
时会创建test_constants_become_symbols
符号。然后,当您运行它时,调用Symbol.all_symbols
以获取所有已知符号的列表,并且:nonexistent
在列表中。另请注意,"nonexistent"
上的双引号是语法问题,而不是内部表示问题,因此:nonexistent
和:"nonexistent"
是相同的。
如果你注释掉这个:
assert_equal true, all_symbols.include?(:"What is the sound of one hand clapping?")
然后解析器将看不到:"What is the sound of one hand clapping?"
符号,因此它不会在all_symbols
数组中。执行.to_sym
时,将执行以下行中的test_constants_become_symbols
方法调用;因此,:"What is the sound of one hand clapping?"
符号是在您获得all_symbols
之后创建的,这将失败:
assert_equal true, all_symbols.include?("What is the sound of one hand clapping?".to_sym)
如果您在同一个解释器实例中再次执行test_constants_become_symbols
(第二个assert_equal
仍然已注释掉),则两个未注释的assert_equal
调用将在第一次通过{{1}时通过}将创建test_constants_become_symbols
,第二个:"What is the sound of one hand clapping?"
将其包含在返回的数组中。
在Symbol.all_symbols
中运行代码而不将其包装在irb
中可能有助于您了解正在发生的事情。
答案 1 :(得分:3)
我不是Ruby大师,但看起来解释器在def
表达式评估期间创建了这个符号。这就是当你致电Symbol.all_symbols
时这些符号已经存在的原因。第三个assert
失败,第二个被注释掉,因为"string".to_sym
在方法执行期间创建了符号,即在您获得带有all_symbols = Symbol.all_symbols
的符号之后。