我的问题建立在这个问题上:Ruby Koan: Constants become symbols。我有以下代码:
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)
提前道歉,问一个简单的“是或否”问题。我很好奇知道“正确”的答案是什么。我本来希望在我上面提到的上一篇文章的评论中提出这个问题,但我不能不单独发帖。
答案 0 :(得分:9)
这是我得到的:
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
答案 1 :(得分:5)
注意:以下答案仅适用于像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
进行这些调用,但不是解决此问题所必需的。
答案 2 :(得分:4)
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]
但现在,有一个问题。
Symbol.all_symbols.include?(:DoesNotMatter)
在运行此代码之前,:DoesNotMatter
中不存在all_symbols
,但它仍然存在。好吧,实际上当你使用符号文字时,它被插入Symbol.all_symbols
(除非它已经存在)。因此,在您调用.include?
之前,符号已经存在。
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>