루비에서 기호를 해시 키로 사용하는 이유는 무엇입니까?
사람들은 루비 해시에서 기호를 키로 사용하는 경우가 많습니다.
끈을 사용하면 어떤 장점이 있습니까?
예:
hash[:name]
대.
hash['name']
TL;DR:
기호를 사용하면 비교할 때 시간이 절약될 뿐만 아니라 한 번만 저장되므로 메모리도 절약됩니다.
루비 기호는 불변(변경할 수 없음)이므로 검색하기가 훨씬 쉽습니다.
짧은 대답:
기호를 사용하면 비교할 때 시간이 절약될 뿐만 아니라 한 번만 저장되므로 메모리도 절약됩니다.
Ruby의 기호는 기본적으로 "불변의 문자열"입니다. 즉, 변경할 수 없습니다. 소스 코드 전체에서 여러 번 참조할 때 동일한 기호가 항상 동일한 엔티티(예: 동일한 개체 ID)로 저장됩니다.
a = 'name'
a.object_id
=> 557720
b = 'name'
=> 557740
'name'.object_id
=> 1373460
'name'.object_id
=> 1373480 # !! different entity from the one above
# Ruby assumes any string can change at any point in time,
# therefore treating it as a separate entity
# versus:
:name.object_id
=> 71068
:name.object_id
=> 71068
# the symbol :name is a references to the same unique entity
반면에 줄은 변형이 가능하고 언제든지 바꿀 수 있습니다.즉, Ruby는 소스 코드 전체에서 언급한 각 문자열을 별도의 엔티티에 저장해야 합니다. 예를 들어, 소스 코드에 여러 번 언급된 문자열 "이름"이 있는 경우, 나중에 변경될 수 있기 때문에 Ruby는 이 모든 문자열을 별도의 String 개체에 저장해야 합니다(Ruby 문자열의 특성).
문자열을 해시 키로 사용하는 경우, Ruby는 문자열을 평가하고 해당 문자열의 내용을 확인(그리고 해시 함수를 계산)하고 해시에 이미 저장되어 있는 키의 해시 값과 결과를 비교해야 합니다.
만약 당신이 해시 키로 기호를 사용한다면, 그것은 불변이라는 것을 암시하기 때문에, 루비는 기본적으로 해시에 이미 저장된 키의 (해시된) 객체-id와 (훨씬 더 빨리) 비교할 수 있습니다.
단점:각 기호는 루비 인터프리터의 기호 테이블에 있는 슬롯을 사용하며, 이 슬롯은 해제되지 않습니다.기호는 절대 가비지 수집되지 않습니다.따라서 많은 수의 기호(예: 자동 생성된 기호)가 있는 경우가 있습니다.이 경우 Ruby 인터프리터의 크기에 미치는 영향을 평가해야 합니다(예: 너무 많은 기호를 프로그래밍 방식으로 생성하면 Ruby 메모리가 부족해지고 폭발할 수 있습니다).
주의:
문자열 비교를 수행하면 Ruby는 객체 ID를 평가할 필요 없이 객체 ID를 비교하는 것만으로 기호를 비교할 수 있습니다.그것은 평가가 필요한 문자열을 비교하는 것보다 훨씬 빠릅니다.
만약 당신이 해시에 접근한다면, Ruby는 당신이 사용하는 모든 키에서 "해시 키"를 계산하기 위해 항상 해시 함수를 적용합니다.여러분은 MD5 해시와 같은 것을 상상할 수 있습니다.그런 다음 루비는 "해시된 키"를 서로 비교합니다.
코드에서 문자열을 사용할 때마다 새 인스턴스가 생성됩니다. 문자열 작성 속도는 기호를 참조하는 속도보다 느립니다.
Ruby 2.1부터는 고정 문자열을 사용할 때 Ruby가 동일한 문자열 개체를 사용합니다.이렇게 하면 동일한 문자열의 새 복사본을 만들 필요가 없으며 가비지가 수집된 공간에 저장됩니다.
긴 답변:
https://www.rubyguides.com/2016/01/ruby-mutability/
그 이유는 효율성과 문자열에 대한 여러 가지 이점 때문입니다.
- 기호는 불변이므로 "키가 변경되면 어떻게 됩니까?"라는 질문을 할 필요가 없습니다.
- 문자열은 코드에서 중복되며 일반적으로 메모리에 더 많은 공간을 차지합니다.
- 해시 검색은 키를 비교하기 위해 키의 해시를 계산해야 합니다.는 이은입니다.
O(n)
문자열의 경우 및 기호의 경우 상수입니다.
는 기호했습니다(예: Ruby 1.9 예기키호가키 (다: 기호또: 니한습했).h.merge(foo: 42, bar: 6)
) 및 Ruby 2.0에는 기호 키에만 사용할 수 있는 키워드 인수가 있습니다.
참고:
루비가 치료한다는 것을 알면 놀랄지도 모릅니다.String
키가 다른 유형과 다릅니다.실제로:
s = "foo"
h = {}
h[s] = "bar"
s.upcase!
h.rehash # must be called whenever a key changes!
h[s] # => nil, not "bar"
h.keys
h.keys.first.upcase! # => TypeError: can't modify frozen string
문자열 키의 경우에만 개체 자체 대신 고정된 복사본을 사용합니다.
문자 "b", "a" 및 "r"은 모든 발생에 대해 한 번만 저장됩니다.:bar
에는 새로운 Ruby 2.2를 않았습니다.Symbols
글로벌 심볼 조회 테이블에 영원히 남아 있기 때문에 재사용되지 않았습니다.Ruby 2.2는 쓰레기를 수거할 것이므로 걱정할 필요가 없습니다.
실제로 Ruby 1.8.x에서는 객체 ID가 직접 사용되었기 때문에 심볼의 해시를 계산하는 데 시간이 걸리지 않았습니다.
:bar.object_id == :bar.hash # => true in Ruby 1.8.7
1가 한 세션으로 변경됨에 따라 변경되었습니다(Ruby 19.x의 세션 ).Symbols
):
:bar.hash # => some number that will be different next time Ruby 1.9 is ran
Re: 문자열을 사용하면 어떤 이점이 있습니까?
- 스타일링: 루비웨이입니다.
(매우) 기호 해시는 정수 해시 대 문자열 해시와 동일하므로 값 조회 속도가 약간 빠릅니다.
단점: 프로그램의 심볼 테이블에서 해제되지 않은 슬롯을 사용합니다.
루비 2.x에 도입된 frozen string에 대한 후속 조치에 관심이 많습니다.
텍스트 입력에서 오는 수많은 문자열(예: 랙을 통해 HTTP 매개 변수 또는 페이로드를 생각하고 있습니다)을 처리할 때 모든 곳에서 문자열을 사용하는 것이 훨씬 쉽습니다.
여러분이 수십 개의 단어들을 다루지만 결코 변하지 않을 때(만약 그것들이 여러분의 비즈니스 "어휘"라면), 저는 그것들을 동결하는 것이 차이를 만들 수 있다고 생각합니다.아직 벤치마크를 해본 적은 없지만 심볼 성능에 근접할 것 같습니다.
언급URL : https://stackoverflow.com/questions/8189416/why-use-symbols-as-hash-keys-in-ruby
'programing' 카테고리의 다른 글
write(write) 대 writeline(write string (0) | 2023.07.21 |
---|---|
Oracle에서 IPv4/IPv6 주소 표시 (0) | 2023.07.21 |
Oracle: 'order by' 절이 있는 행 번호 표시 (0) | 2023.07.21 |
Tomcat에 배포된 스프링 부트는 404개를 제공하지만 독립 실행형으로 작동합니다. (0) | 2023.07.21 |
@Spring Boot 2.6.0에서 실패한 테스트에서 자동 구성 사용(=... 제외) (0) | 2023.07.21 |