Neden sembolleri Ruby'de karma anahtar olarak kullanmalıyım?


162

Çoğu zaman insanlar Ruby karma işleminde sembolleri anahtar olarak kullanır.

Dize kullanmanın avantajı nedir?

Örneğin:

hash[:name]

vs.

hash['name']

Yanıtlar:


227

TL; DR:

Sembolleri kullanmak sadece karşılaştırma yaparken zamandan tasarruf etmekle kalmaz, aynı zamanda hafızadan da tasarruf sağlar, çünkü bunlar sadece bir kez saklanır.

Ruby Sembolleri değişmezdir (değiştirilemez), bu da bir şeyi daha kolay aramanızı sağlar

Kısa (ish) cevap:

Sembolleri kullanmak sadece karşılaştırma yaparken zamandan tasarruf etmekle kalmaz, aynı zamanda hafızadan da tasarruf sağlar, çünkü bunlar sadece bir kez saklanır.

Ruby'deki semboller temel olarak "değiştirilemeyen dizelerdir" , yani değiştirilemeyecekleri anlamına gelir ve kaynak kodunuz boyunca birçok kez referans verildiğinde aynı sembolün her zaman aynı varlık olarak depolandığını, örneğin aynı nesne kimliğine sahip olduğunu gösterir. .

Öte yandan dizeler değiştirilebilir , her zaman değiştirilebilir. Bu, Ruby'nin bahsettiğiniz her bir dizeyi kaynak kodunuz boyunca ayrı bir varlıkta saklaması gerektiği anlamına gelir; örneğin, kaynak kodunuzda birden çok kez bir "ad" dizesi varsa, Ruby bunların tümünü ayrı String nesnelerine depolaması gerekir, çünkü bunlar daha sonra değişebilir (bu bir Ruby dizesinin doğasıdır).

Bir dizeyi Hash anahtarı olarak kullanırsanız, Ruby'nin dizeyi değerlendirmesi ve içeriğine bakması (ve bunun üzerinde bir hash işlevi hesaplaması) ve sonucu Hash'te zaten saklanan tuşların (hashed) değerleriyle karşılaştırması gerekir. .

Bir sembolü Hash anahtarı olarak kullanırsanız, değiştirilemez olduğu anlaşılır, böylece Ruby temel olarak, zaten depolanmış olan anahtarların (hashed) nesne kimlikleriyle (hashed) nesne kimlikleriyle bir karşılaştırma yapabilir. Hash. (Çok daha hızlı)

Dezavantajı: Her sembol, Ruby yorumlayıcısının sembol tablosunda asla serbest bırakılmayan bir yuva tüketir. Semboller asla çöp toplanmaz. Yani bir köşe durumu, çok sayıda sembolünüz olduğundadır (örneğin, otomatik olarak oluşturulan semboller). Bu durumda, bunun Ruby yorumcunuzun boyutunu nasıl etkilediğini değerlendirmelisiniz.

Notlar:

Dize karşılaştırmaları yaparsanız, Ruby sembolleri değerlendirmek zorunda kalmadan yalnızca nesne kimlikleriyle karşılaştırabilir. Bu, değerlendirilmesi gereken dizeleri karşılaştırmaktan çok daha hızlıdır.

Bir karmaya erişirseniz, Ruby her hangi bir tuştan "karma anahtarı" hesaplamak için her zaman karma işlevini uygular. MD5 karma gibi bir şey hayal edebilirsiniz. Ve sonra Ruby bu "karma anahtarları" birbirleriyle karşılaştırır.

Uzun cevap:

https://web.archive.org/web/20180709094450/http://www.reactive.io/tips/2009/01/11/the-difference-between-ruby-symbols-and-strings

http://www.randomhacks.net.s3-website-us-east-1.amazonaws.com/2007/01/20/13-ways-of-looking-at-a-ruby-symbol/


5
Fyi, Semboller Ruby'nin bir sonraki sürümünde GCd olacak: bugs.ruby-lang.org/issues/9634
Ajedi32

2
Ayrıca, Ruby'de Hash tuşları olarak kullanıldığında dizeler otomatik olarak dondurulur. Dolayısıyla, bu bağlamda onlardan bahsederken Dizelerin değiştirilebilir olduğu tam olarak doğru değildir.
Ajedi32

1
"Uzun cevap" bölümündeki konuyla ilgili ilk bağlantı kaldırıldı veya taşındı.
Hbksagar

2
Semboller Ruby 2.2'de toplanan
çöplerdir

2
Mükemmel cevap! Bir trolling tarafında, "kısa cevabınız" da yeterince uzun. ;)
technophyle

22

Bunun nedeni, bir String üzerinden birden fazla kazanım ile verimliliktir:

  1. Semboller değiştirilemez, bu yüzden "anahtar değişirse ne olur?" Sorusu. sorulmasına gerek yok.
  2. Dizeler kodunuzda çoğaltılır ve genellikle bellekte daha fazla yer kaplar.
  3. Hash aramaları, karşılaştırmak için anahtarların karmasını hesaplamalıdır. Bu, O(n)Dizeler için ve Semboller için sabittir.

Dahası, Ruby 1.9 sadece sembol tuşları ile karma için basitleştirilmiş bir sözdizimi getirdi (örneğin h.merge(foo: 42, bar: 6)) ve Ruby 2.0 sadece sembol tuşları için çalışan anahtar kelime argümanlarına sahiptir.

Notlar :

1) Ruby'nin Stringtuşlara diğer türlerden farklı davrandığını öğrenmek sizi şaşırtabilir . Aslında:

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

Yalnızca dize anahtarları için Ruby nesnenin kendisi yerine dondurulmuş bir kopya kullanır.

2) "b", "a" ve "r" harfleri :barbir programdaki tüm oluşumlar için yalnızca bir kez kaydedilir . Ruby 2.2'den önce, Symbolssonsuza dek küresel Sembol arama tablosunda kalacağından, asla tekrar kullanılmayan yeni ürünler oluşturmak kötü bir fikirdi . Ruby 2.2 onları çöp toplayacak, bu yüzden endişelenmeyin.

3) Aslında, bir Sembol için karmayı hesaplamak, nesne kimliği doğrudan kullanıldığından Ruby 1.8.x'te hiç zaman almadı:

:bar.object_id == :bar.hash # => true in Ruby 1.8.7

Ruby 1.9.x sürümünde, karma değerleri bir oturumdan diğerine değiştikçe (aşağıdakiler dahil Symbols) değişti :

:bar.hash # => some number that will be different next time Ruby 1.9 is ran

Mükemmel notlarınız için +1! Aslında cevabımdaki hash fonksiyonundan bahsetmedim, çünkü okumayı daha kolay hale getirmeye çalıştım :)
Tilo

@Tilo: gerçekten, bu yüzden cevabımı yazdım :-) Sadece cevabımı Ruby
1.9'daki

Karma aramalarının Semboller için sabit olduğunu ve Dizeler için O (n) değerini açıklayabilir misiniz?
Asad Moosvi

7

Re: bir dize kullanmanın avantajı nedir?

  • Stil: bu Ruby yolu
  • (Çok) biraz daha hızlı değer arar, çünkü bir sembolün hash edilmesi, bir tamsayının hash edilmesiyle bir stringin hash edilmesine eşdeğerdir.

  • Dezavantajı: Programın sembol tablosunda asla serbest bırakılmayan bir yuva tüketir.


4
Sembolün asla çöp toplanmadığını belirtmek için +1.
Vortico

sembol asla çöp toplanmaz - yakut 2.2'den beri doğru değil
eudaimonia

0

Ruby 2.x'te tanıtılan donmuş tellerle ilgili bir takiple çok ilgilenirim.

Bir metin girişinden gelen çok sayıda dizeyle uğraştığınızda (örneğin HTTP paramleri veya yükü düşünüyorum, örneğin Rack aracılığıyla), her yerde dizeleri kullanmak çok daha kolay.

Düzinelerce ile uğraşırken asla değişmezlerse (eğer işletmeniz "kelime" ise), dondurmanın bir fark yaratabileceğini düşünmek isterim. Henüz bir kıyaslama yapmadım, ama sanırım sembollerin performansı yakın olacaktı.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.