Ruby Koans: зачем преобразовывать список символов в строки - PullRequest
78 голосов
/ 14 января 2011

Я имею в виду этот тест в about_symbols.rb в Ruby Koans 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 ]

104 голосов
/ 14 января 2011

Это связано с тем, как работают символы. Для каждого символа фактически существует только один из них. За кулисами символ - это просто число, на которое ссылается имя (начиная с двоеточия). Таким образом, сравнивая равенство двух символов, вы сравниваете идентичность объекта и , а не содержимое идентификатора, который ссылается на этот символ.

Если вы проведете простой тест : test == "test" , он будет ложным. Таким образом, если бы вы собрали все символы, определенные до сих пор, в массив, вам нужно сначала преобразовать их в строки, прежде чем сравнивать их. Вы не можете сделать это противоположным способом (сначала преобразуйте строку, которую вы хотите сравнить в символ), потому что при этом будет создан единственный экземпляр этого символа и «загрязнена» ваш список символом, который вы проверяете на существование.

Надеюсь, это поможет. Это немного странно, потому что вы должны проверить наличие символа, не создавая случайно этот символ во время теста. Вы обычно не видите такой код.

70 голосов
/ 14 января 2011

Потому что, если вы делаете

assert_equal true, all_symbols.include?(:test_method_names_become_symbols)

это может (в зависимости от вашей реализации ruby) автоматически быть верным, потому что запрос о :test_method_names_become_symbols создает его. См. отчет об ошибке .

3 голосов
/ 13 ноября 2013

Оба ответа выше верны, но в свете вопроса Картика, приведенного выше, я подумал, что опубликую тест, показывающий, как можно точно передать символ методу 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

Дополнительное примечание о коанах: используйте операторы puts, а также пользовательские тесты, если вы ничего не понимаете. Например, если вы видите:

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

и понятия не имею, что может быть words, добавьте строку

puts words

и запустите rake в командной строке. Аналогично, тесты, подобные тому, который я добавил выше, могут быть полезны с точки зрения понимания некоторых нюансов Ruby.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...