[ruby] Ruby에서 기호를 이해하는 방법

Ruby Symbols 이해하기 “를 읽었음에도 불구하고 , 저는 기호 를 사용할 때 메모리의 데이터 표현에 여전히 혼란 스럽습니다. 다른 객체에 포함 된 두 개의 심볼이 동일한 메모리 위치에 존재하는 경우 어떻게 다른 값 을 포함하고 있습니까? 동일한 메모리 위치에 동일한 값이 포함될 것으로 예상했습니다.

이것은 링크의 인용문입니다.

문자열과 달리 동일한 이름의 심볼이 초기화되고 루비 세션 중 한 번만 메모리에 존재합니다.

동일한 메모리 위치에 포함 된 값을 구별하는 방법을 이해하지 못합니다.

이 예를 고려하십시오.

patient1 = { :ruby => "red" }
patient2 = { :ruby => "programming" }

patient1.each_key {|key| puts key.object_id.to_s}
3918094
patient2.each_key {|key| puts key.object_id.to_s}
3918094

patient1그리고 patient2두 해시, 괜찮아요 있습니다. :ruby그러나 상징입니다. 다음을 출력하려면 :

patient1.each_key {|key| puts key.to_s}

그러면 무엇이 출력됩니까? "red", 또는 "programming"?

잠시 해시를 잊어 버리면 기호가 값에 대한 포인터 라고 생각 합니다. 내가 가진 질문은 다음과 같습니다.

  • 기호에 값을 지정할 수 있습니까?
  • 기호는 값이있는 변수에 대한 포인터 일 뿐입니 까?
  • 심볼이 전역이라면 심볼이 항상 한 가지를 가리킴을 의미합니까?



답변

이걸 고려하세요:

x = :sym
y = :sym
(x.__id__ == y.__id__ ) && ( :sym.__id__ == x.__id__) # => true

x = "string"
y = "string"
(x.__id__ == y.__id__ ) || ( "string".__id__ == x.__id__) # => false

따라서 심볼 객체를 만들면 내용이 동일하면 메모리에서 동일한 객체를 참조합니다. 심볼은 불변 객체 이기 때문에 문제가되지 않습니다 . 문자열은 변경 가능합니다.


(아래 댓글에 대한 답변)

원본 기사에서 값은 기호에 저장되지 않고 해시에 저장됩니다. 이걸 고려하세요:

hash1 = { "string" => "value"}
hash2 = { "string" => "value"}

이것은 메모리에 4 개의 문자열 객체와 2 개의 해시 객체의 6 개의 객체를 생성합니다.

hash1 = { :symbol => "value"}
hash2 = { :symbol => "value"}

이것은 메모리에 5 개의 객체 (심볼 1 개, 문자열 2 개, 해시 객체 2 개) 만 생성합니다.


답변

이런 식으로 생각하면 상징물을 그을 릴 수있었습니다. Ruby 문자열은 메서드와 속성이 많은 객체입니다. 사람들은 키에 문자열을 사용하는 것을 좋아하고 문자열이 키에 사용되면 이러한 모든 추가 메서드가 사용되지 않습니다. 그래서 그들은 좋은 키가되기 위해 필요한 것을 제외하고 모든 기능이 제거 된 문자열 객체 인 심볼을 만들었습니다.

기호를 상수 문자열로 생각하면됩니다.


답변

기호는 :ruby포함하지 않는 "red""programming". 상징 :ruby은 단지 상징 :ruby입니다. 그것은 당신의 해시입니다, patient1그리고 patient2각각 그 값을 포함하는 것으로, 각각의 경우에 동일한 키에 의해 지적했다.

다음과 같이 생각해보십시오. 크리스마스 아침에 거실에 들어가서 “Kezzer”라고 적힌 태그가있는 상자 두 개를 본다면. On에는 양말이 있고 다른 하나에는 석탄이 있습니다. 이름이 같더라도 “Kezzer”가 어떻게 양말과 석탄을 모두 포함 할 수 있는지 혼동하지 않을 것입니다. 이름에 (엉뚱한) 선물이 포함되어 있지 않기 때문입니다. 그것은 단지 그들을 가리키는 것입니다. 마찬가지로 :ruby해시의 값을 포함하지 않고 해당 값을 가리 킵니다.


답변

당신은 당신이 만든 선언이 Symbol의 가치를 그것이 무엇인지 아닌 다른 것으로 정의한다고 가정 할 수 있습니다. 실제로 Symbol은 일정하게 유지되는 “내부화 된”문자열 값입니다. 많은 수의 가변 길이 문자열을 관리하는 것보다 효율적으로 자주 사용되는 간단한 정수 식별자를 사용하여 저장되기 때문입니다.

귀하의 예를 들어보십시오.

patient1 = { :ruby => "red" }

이것은 “patient1 변수를 선언하고 해시로 정의하고,이 저장소에서 키 아래에 ‘red’값 (기호 ‘ruby’)”으로 읽어야합니다.

이것을 작성하는 또 다른 방법은 다음과 같습니다.

patient1 = Hash.new
patient1[:ruby] = 'red'

puts patient1[:ruby]
# 'red'

할당을 할 때 반환되는 결과가 처음에 할당 한 결과와 동일하다는 것은 놀라운 일이 아닙니다.

Symbol 개념은 대부분의 다른 언어의 기능이 아니기 때문에 약간 혼란 스러울 수 있습니다.

값이 동일하더라도 각 String 객체는 구별됩니다.

[ "foo", "foo", "foo", "bar", "bar", "bar" ].each do |v|
  puts v.inspect + ' ' + v.object_id.to_s
end

# "foo" 2148099960
# "foo" 2148099940
# "foo" 2148099920
# "bar" 2148099900
# "bar" 2148099880
# "bar" 2148099860

동일한 값을 가진 모든 기호는 동일한 객체를 참조합니다.

[ :foo, :foo, :foo, :bar, :bar, :bar ].each do |v|
  puts v.inspect + ' ' + v.object_id.to_s
end

# :foo 228508
# :foo 228508
# :foo 228508
# :bar 228668
# :bar 228668
# :bar 228668

문자열을 기호로 변환하면 동일한 값이 동일한 고유 기호에 매핑됩니다.

[ "foo", "foo", "foo", "bar", "bar", "bar" ].each do |v|
  v = v.to_sym
  puts v.inspect + ' ' + v.object_id.to_s
end

# :foo 228508
# :foo 228508
# :foo 228508
# :bar 228668
# :bar 228668
# :bar 228668

마찬가지로 Symbol에서 String으로 변환하면 매번 고유 한 문자열이 생성됩니다.

[ :foo, :foo, :foo, :bar, :bar, :bar ].each do |v|
  v = v.to_s
  puts v.inspect + ' ' + v.object_id.to_s
end

# "foo" 2148097820
# "foo" 2148097700
# "foo" 2148097580
# "bar" 2148097460
# "bar" 2148097340
# "bar" 2148097220

Symbol 값은 내부 Hash 테이블에서 가져온 것으로 생각할 수 있으며 간단한 메서드 호출을 사용하여 Symbols로 인코딩 된 모든 값을 볼 수 있습니다.

Symbol.all_values

# => [:RUBY_PATCHLEVEL, :vi_editing_mode, :Separator, :TkLSHFT, :one?, :setuid?, :auto_indent_mode, :setregid, :back, :Fail, :RET, :member?, :TkOp, :AP_NAME, :readbyte, :suspend_context, :oct, :store, :WNOHANG, :@seek, :autoload, :rest, :IN_INPUT, :close_read, :type, :filename_quote_characters=, ...

콜론 표기법이나 .to_sym을 사용하여 새 기호를 정의하면이 테이블이 커집니다.


답변

기호는 포인터가 아닙니다. 값을 포함하지 않습니다. 기호는 간단 하다 . :ruby상징 :ruby이고 그게 전부입니다. 그것은하지 않습니다 값을 포함하지 않는 수행 은 단지 상징으로 존재, 아무것도 :ruby. 기호 :ruby는 숫자 1과 같은 값입니다. 숫자 1이하는 것보다 더 다른 값을 가리 키지 않습니다.


답변

patient1.each_key {|key| puts key.to_s}

그러면 무엇이 출력됩니까? “빨간색”또는 “프로그래밍”?

둘 다 “루비”를 출력합니다.

기호와 해시를 혼동하고 있습니다. 관련이 없지만 함께 유용합니다. 문제의 기호는 다음과 같습니다 :ruby. 해시의 값과 관련이 없으며 내부 정수 표현은 항상 동일하며 “값”(문자열로 변환 될 때)은 항상 “루비”가됩니다.


답변

간단히 말해서

심볼은 사람이 읽을 수 있고 변경할 수없는 표현을 만드는 문제를 해결하며 런타임이 문자열보다 조회하는 것이 더 간단하다는 이점도 있습니다. 재사용 할 수있는 이름이나 레이블로 생각하십시오.

왜 : red가 “red”보다 낫다

동적 객체 지향 언어에서는 읽을 수있는 참조로 복잡하고 중첩 된 데이터 구조를 만듭니다. 해시는 일반적인 사용 사례입니다 이상, 각 인스턴스에 고유 한 – 당신이 고유 키 값을 매핑합니다. 해시 당 하나 이상의 “빨간색”키를 가질 수 없습니다.

그러나 문자열 키 대신 숫자 인덱스를 사용하는 것이 더 프로세서 효율적입니다. 따라서 기호는 속도와 가독성 사이의 절충안으로 도입되었습니다. 기호는 동등한 문자열보다 훨씬 쉽게 해석됩니다. 사람이 읽을 수 있고 런타임에서 기호를 쉽게 확인할 수 있으므로 동적 언어에 이상적인 추가 기능입니다.

혜택

심볼은 변경 불가능하므로 런타임에서 공유 할 수 있습니다. 두 개의 해시 인스턴스가 빨간색 항목에 대한 공통 사전 적 또는 의미 론적 필요를 갖는 경우 : red 기호는 두 개의 해시에 대해 문자열 “red”가 필요로하는 메모리의 약 절반을 사용합니다.

: red는 항상 메모리의 동일한 위치로 다시 확인되므로 메모리를 거의 늘리지 않고 백 개의 해시 인스턴스에서 재사용 할 수 있지만 “red”를 사용하면 각 해시 인스턴스가 변경 가능한 문자열을 저장해야하기 때문에 메모리 비용이 추가됩니다. 창조.

Ruby가 실제로 심볼 / 문자열을 구현하는 방법은 확실하지 않지만 심볼은 고정 된 표현이기 때문에 런타임에서 구현 오버 헤드가 적습니다. 더하기 기호는 따옴표로 묶인 문자열보다 입력하는 데 문자가 하나 더 적으며, 더 적은 입력은 진정한 Rubyists의 영원한 추구입니다.

요약

: red와 같은 기호를 사용하면 문자열 비교 작업의 비용과 각 문자열 인스턴스를 메모리에 저장해야하기 때문에 오버 헤드가 적은 문자열 표현의 가독성을 얻을 수 있습니다.