Ruby Koans#75 test_constants_become_symbols,正确答案?

Joo*_*hin 10 ruby 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
Run Code Online (Sandbox Code Playgroud)

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

    assert_equal true, all_symbols.include?("RubyConstant".to_sym)
Run Code Online (Sandbox Code Playgroud)

我知道我不应该这样做:

    assert_equal true, all_symbols.include?(:RubyConstant)
Run Code Online (Sandbox Code Playgroud)

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

    assert_equal true, all_symbols.include?(:DoesNotMatter)
Run Code Online (Sandbox Code Playgroud)

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

Eya*_*lan 10

这是我得到的:

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
Run Code Online (Sandbox Code Playgroud)


Kon*_*ski 5

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

irb(main):001:0> Constant = 42
=> 42
irb(main):002:0> Symbol.all_symbols
=> [:"", :"<IFUNC>", :"<CFUNC>", :respond_to?,  ..., :irb_exit_org, :Constant]
Run Code Online (Sandbox Code Playgroud)

但是现在有一个陷阱。

Symbol.all_symbols.include?(:DoesNotMatter)
Run Code Online (Sandbox Code Playgroud)

在运行此代码之前,该代码: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>
Run Code Online (Sandbox Code Playgroud)


Gre*_*own 5

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

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

assert_equal true, all_symbols.include?(:RubyConstant)
Run Code Online (Sandbox Code Playgroud)

我认为这是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
Run Code Online (Sandbox Code Playgroud)

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