Ruby Koan: Константы становятся символами
В about_symbols.rb Ruby Koan (https://github.com/edgecase/ruby_koans) у меня есть следующий код:
RubyConstant = "What is the sound of one hand clapping?"
def test_constants_become_symbols
all_symbols = Symbol.all_symbols
assert_equal true, all_symbols.include?(:"nonexistent")
assert_equal true, all_symbols.include?(:"What is the sound of one hand clapping?")
assert_equal true, all_symbols.include?("What is the sound of one hand clapping?".to_sym)
end
Как есть, тест проходит.
Три вопроса:
-
Почему первое утверждение проходит? :"nonexistent"
не следует включать в all_symbols, но он включен, поэтому я должен что-то недопонимать.
-
Когда я комментирую второе утверждение, тест терпит неудачу, потому что "What is the sound of one hand clapping?".to_sym
не включен во все_символы, тогда как :"What is the sound of one hand clapping?"
включен. Поскольку они эквивалентны, почему последнее утверждение терпит неудачу? Кроме того, почему это происходит, когда второе утверждение не закомментировано? (Почему второе утверждение влияет на третье утверждение?)
-
Насколько я знаю, суть этого Ruby Koan заключалась в том, чтобы продемонстрировать, что константы становятся символами (по крайней мере, то, что я выводил из имени метода). Поскольку RubyConstant является константой со значением "What is the sound of one hand clapping?"
, почему нет "What is the sound of one hand clapping?".to_sym
, включенного в список символов? Единственное объяснение, о котором я могу думать, это то, что, вопреки имени метода, константы фактически не становятся символами.
Спасибо за вашу помощь!
Ответы
Ответ 1
hoha имеет это право, но я попытаюсь немного расширить и пояснить.
Интерпретатор создает символ :nonexistent
, когда он анализирует test_constants_become_symbols
. Затем, когда вы запустите его, вызывается Symbol.all_symbols
, чтобы получить список всех известных символов, а :nonexistent
- в списке. Также обратите внимание, что двойные кавычки на "nonexistent"
являются проблемой синтаксиса, а не проблемой внутреннего представления, поэтому :nonexistent
и :"nonexistent"
- это одно и то же.
Если вы закомментируете это:
assert_equal true, all_symbols.include?(:"What is the sound of one hand clapping?")
тогда символ :"What is the sound of one hand clapping?"
не будет восприниматься синтаксическим анализатором, поэтому он не будет находиться в массиве all_symbols
. Вызов метода .to_sym
в следующей строке выполняется, когда выполняется test_constants_become_symbols
; поэтому символ :"What is the sound of one hand clapping?"
создается после того, как вы получите all_symbols
, и это не сработает:
assert_equal true, all_symbols.include?("What is the sound of one hand clapping?".to_sym)
Если вы выполните test_constants_become_symbols
снова в том же экземпляре интерпретатора (со вторым assert_equal
все еще закомментированным), то оба uncommented assert_equal
вызова пройдут, так как первый прогон через test_constants_become_symbols
приведет к созданию :"What is the sound of one hand clapping?"
и второй Symbol.all_symbols
будет включать его в возвращенный массив.
Запуск кода в irb
без его упаковки в def
может помочь вам понять, что происходит.
Ответ 2
Я не гуру Ruby, но похоже, что интерпретатор создал эти символы во время оценки выражения def
. Вот почему эти символы уже существуют, когда вы вызываете Symbol.all_symbols
. Третий assert
выходит из строя, а второй закомментирован, потому что "string".to_sym
создает символ во время выполнения методов, т.е. После того, как вы получили доступные символы с all_symbols = Symbol.all_symbols
.