Ruby Koans:为什么要将符号列表转换为字符串

时间:2011-01-13 22:33:08

标签: ruby

我指的是Ruby Koans中about_symbols.rb中的这个测试 https://github.com/edgecase/ruby_koans/blob/master/src/about_symbols.rb#L26

def test_method_names_become_symbols
  symbols_as_strings = Symbol.all_symbols.map { |x| x.to_s }
  assert_equal true, symbols_as_strings.include?("test_method_names_become_symbols")
end


  # THINK ABOUT IT:
  #
  # Why do we convert the list of symbols to strings and then compare
  # against the string value rather than against symbols?

为什么我们必须先将该列表转换为字符串?

3 个答案:

答案 0 :(得分:103)

这与符号的工作方式有关。对于每个符号,实际上只存在其中一个符号。在幕后,符号只是一个名称引用的数字(以冒号开头)。因此,在比较两个符号的相等性时,您要比较对象标识和引用此符号的标识符的内容。

如果您要进行简单测试:test ==“test”,则该测试将为false。因此,如果要将到目前为止定义的所有符号收集到一个数组中,则需要先将它们转换为字符串,然后再进行比较。您不能以相反的方式执行此操作(首先将要比较的字符串转换为符号),因为这样做会创建该符号的单个实例,并使用您正在测试存在的符号“污染”您的列表。 / p>

希望有所帮助。这有点奇怪,因为您必须测试符号的存在而不会在测试期间意外创建该符号。你通常看不到那样的代码。

答案 1 :(得分:70)

因为如果你这样做

assert_equal true, all_symbols.include?(:test_method_names_become_symbols)

它可能(取决于您的ruby实现)自动成立,因为询问:test_method_names_become_symbols会创建它。请参阅this bug report

答案 2 :(得分:3)

上面的两个答案都是正确的,但鉴于上面的Karthik的问题,我想我会发布一个测试,说明如何准确地将符号传递给include方法

def test_you_create_a_new_symbol_in_the_test
  array_of_symbols = []
  array_of_symbols << Symbol.all_symbols
  all_symbols = Symbol.all_symbols.map {|x| x}
  assert_equal false, array_of_symbols.include?(:this_should_not_be_in_the_symbols_collection)  #this works because we stored all symbols in an array before creating the symbol :this_should_not_be_in_the_symbols_collection in the test
  assert_equal true, all_symbols.include?(:this_also_should_not_be_in_the_symbols_collection) #This is the case noted in previous answers...here we've created a new symbol (:this_also_should_not_be_in_the_symbols_collection) in the test and then mapped all the symbols for comparison. Since we created the symbol before querying all_symbols, this test passes.
end

关于Koans的另一个注意事项:如果您不理解任何内容,请使用puts语句以及自定义测试。例如,如果您看到:

string = "the:rain:in:spain"
words = string.split(/:/)

并且不知道words可能是什么,添加行

puts words

并在命令行运行rake。同样,我在上面添加的测试可以帮助理解Ruby的一些细微差别。