Ruby Koans#75 test_constants_become_symbols,正确答案?

我的问题建立在这个问题的基础上: Ruby Koan:常数成为符号 。 我有以下代码:

in_ruby_version("mri") do RubyConstant = "What is the sound of one hand clapping?" def test_constants_become_symbols all_symbols = Symbol.all_symbols assert_equal __, all_symbols.include?(__) end end 

应该是正确的答案如下吗?

  assert_equal true, all_symbols.include?("RubyConstant".to_sym) 

我知道我不应该这样做:

  assert_equal true, all_symbols.include?(:RubyConstant) 

因为那时我可以放任何东西,它仍然是真的

  assert_equal true, all_symbols.include?(:DoesNotMatter) 

提前道歉,问一个简单的“是或否”问题。 我很好奇知道“正确”的答案是什么。 我宁愿在上面提到的上一篇文章的评论中提出这个问题,但我不能不另外发表一篇文章。

注意:以下答案仅适用于像irb这样的环境,其中Ruby代码是逐行执行的。 在文件中执行代码时,Ruby会在执行任何操作之前扫描整个文件中的符号,因此以下详细信息不准确。 我没有删除这个答案,因为它暴露了一个有趣的边缘情况,但请参阅@GlichMr的答案以更好地解释问题。

您可以安全地执行以下操作,因为Symbol.all_symbols返回符号数组的副本,而不是引用。

 assert_equal true, all_symbols.include?(:RubyConstant) 

我认为这是koan的预期答案,这就是定义all_symbols而不是直接调用Symbol.all_symbols的原因。 有关证据,请参阅以下内容:

 >> X = 1 => 1 >> all_symbols = Symbol.all_symbols; nil => nil >> Y = 2 => 2 >> all_symbols.include?(:X) => true >> all_symbols.include?(:Y) => false 

使用String#to_sym可以直接对Symbol.all_symbols进行这些调用,但不是解决这个koan所必需的。

这是我得到的:

 in_ruby_version("mri") do RubyConstant = "What is the sound of one hand clapping?" def test_constants_become_symbols all_symbols_as_strings = Symbol.all_symbols.map { |x| x.to_s } assert_equal true, all_symbols_as_strings.include?("RubyConstant") end end 

Symbol.all_symbols包含引用的每个符号 – 变量名,类名,常量名,实际符号。 该变量实际包含的是实现定义,但在Ruby MRI中,许多符号已经在此列表中。

 irb(main):001:0> Constant = 42 => 42 irb(main):002:0> Symbol.all_symbols => [:"", :"", :"", :respond_to?, ..., :irb_exit_org, :Constant] 

但现在,有一个问题。

 Symbol.all_symbols.include?(:DoesNotMatter) 

在您运行此代码之前, :DoesNotMatter中不存在all_symbols ,但它仍然存在。 好吧,实际上当你使用符号文字时,它会被插入到Symbol.all_symbols (除非它已经存在)。 所以,在你打电话之前,这个符号已经在这里了.include?

编辑:格雷戈里布朗建议以下解决方法。 它起作用,因为在Ruby中, Symbol.all_symbols赋值由于某种原因而不是复制对变量的引用而复制变量。

 irb(main):001:0> symbols = Symbol.all_symbols; 1 => 1 irb(main):002:0> symbols.include? :something => false irb(main):003:0>