Ruby Koans : 기호 목록을 문자열로 변환하는 이유


85

Ruby Koans https://github.com/edgecase/ruby_koans/blob/master/src/about_symbols.rb#L26의 about_symbols.rb에서이 테스트를 참조하고 있습니다.

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?

그 목록을 먼저 문자열로 변환해야하는 이유는 무엇입니까?

답변:


110

이것은 기호가 작동하는 방식과 관련이 있습니다. 각 기호에 대해 실제로는 하나만 존재합니다. 이면에서 기호는 이름 (콜론으로 시작)으로 참조되는 숫자입니다. 따라서 두 기호의 동일성을 비교할 때이 기호를 참조하는 식별자의 내용이 아니라 객체 ID를 비교 하는 것입니다.

간단한 테스트를했다면 : test == "test" 는 거짓이됩니다. 따라서 지금까지 정의 된 모든 기호를 배열로 모으려면 비교하기 전에 먼저 문자열로 변환해야합니다. 그렇게하면 해당 심볼의 단일 인스턴스가 생성되고 존재 여부를 테스트하는 심볼로 목록을 "오염"시킬 수 있기 때문에 반대의 방법 (비교하려는 문자열을 먼저 심볼로 변환) 할 수 없습니다.

도움이되기를 바랍니다. 테스트 중에 실수로 심볼을 만들지 않고 심볼의 존재 여부를 테스트해야하기 때문에 이것은 약간 이상한 것입니다. 일반적으로 그런 코드는 표시되지 않습니다.


2
이 작업을 안전하게 수행하는 더 좋은 방법은의 출력을 Symbol.all_symbols변수 에 할당 한 다음 포함 여부를 테스트하는 것입니다. 기호는 비교시 더 빠르며 수천 개의 기호를 문자열로 변환하지 않아도됩니다.
coreyward 2011

4
그것은 여전히 ​​파괴 할 수없는 상징을 만드는 문제를 가지고 있습니다. 해당 기호에 대한 향후 테스트는 망가질 것입니다. 그러나 이것은 단지 Koan 일 뿐이며, 그다지 의미가 없거나 빠를 필요는 없으며 기호가 어떻게 작동하는지 보여줄뿐입니다.
AboutRuby 2011

2
이 대답은 저에게 효과가 없습니다. 기호의 존재를 검색하는 경우 문자열 인수를 지정하는 이유는 다음과 같습니다. include?지정한 경우 :test_method_names_become_symbols모든 기호를 문자열로 변환 할 필요가 없습니다.
Isaac Rabinovitch

3
Isaac, 식별 된 문제 때문에 :test_method_names_become_symbols비교에서 지정하면 문제 가 생성되므로 비교는 항상 참이됩니다. all_symbols문자열 로 변환 하고 문자열을 비교하여 비교 전에 기호가 존재했는지 여부를 구별 할 수 있습니다.
스티븐

3
너무 이해가 안 돼요. >> array_of_symbols = Symbol.all_symbols, >> array_of_symbols.include? (: not_yet_used)를 수행하면 false가되고 정의 된 것에 대해 true가되므로 문자열로의 변환이 필요한 이유를 이해할 수 없습니다. .
codenoob

75

다음과 같은 경우 :

assert_equal true, all_symbols.include?(:test_method_names_become_symbols)

(루비 구현에 따라) :test_method_names_become_symbols기호를 생성 하기 때문에 자동으로 참일 수 있습니다 . 이 버그 보고서를 참조하십시오 .


1
그래서 받아 들여지는 대답은 잘못된 것입니다 (또는 나에게 보입니다).
Isaac Rabinovitch

3
Isaac, 다른 대답은 틀린 것이 아니지만 간결하게 설명되지 않았습니다. 확실히. 어쨌든 다음과 같이 Andrew가 말하는 것을 확인할 수 있습니다. assert_equal true, Symbol.all_symbols.include? (: abcdef) 이것은 기호에 관계없이 항상 통과합니다 (적어도 나를 위해 그렇습니다). 한 가지 교훈은 기호의 유무를 부울 플래그로 사용하지 않는 것입니다.
스티븐

1
2 년이 지난 지금도 저에게 관심이있는이 질문을 보면서이 답변과 의견에 정말 감사드립니다. 나는 Isaac이 옳다고 생각합니다. 이것이 더 잘 작동하도록 중간 단계 (비교 전에 모든 기호를 저장)를 넣을 수 있다고 생각하지만 문자열로의 변환이 왜 갈 길일 수 있는지를 가장 명확하게 설명하는 대답입니다.
codenoob

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의 일부 뉘앙스를 이해하는 데 도움이 될 수 있습니다.


2 년이 지난 지금도 여전히 관심이있는이 질문을 보면서이 답변과 의견에 정말 감사드립니다.
codenoob
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.