在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
Run Code Online (Sandbox Code Playgroud)
按原样,测试通过.
三个问题:
为什么第一个断言通过?:"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
包含在符号列表中?我能想到的唯一解释是,与方法名称相反,常量实际上不会成为符号.
谢谢你的帮助!
哈哈说得对,但我会尝试扩大和澄清一点.
解释器将: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?")
Run Code Online (Sandbox Code Playgroud)
然后:"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)
Run Code Online (Sandbox Code Playgroud)
如果你test_constants_become_symbols
在同一个解释器实例中再次执行(第二个assert_equal
仍然被注释掉),那么两个未注释的assert_equal
调用将通过,因为第一个运行test_constants_become_symbols
将创建:"What is the sound of one hand clapping?"
,第二个Symbol.all_symbols
将包含在返回的数组中.
在irb
没有包装代码的情况下运行代码def
可能会帮助您了解正在发生的事情.
我不是 Ruby 专家,但看起来解释器在def
表达式求值期间创建了这个符号。这就是为什么当您调用 时这些符号已经存在Symbol.all_symbols
。第三次assert
失败,第二次被注释掉,因为"string".to_sym
在方法执行期间创建符号,即在使用 获得可用符号之后all_symbols = Symbol.all_symbols
。