Yanıtlar:
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:
Bunun nedeni, bir String üzerinden birden fazla kazanım ile verimliliktir:
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 String
tuş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 :bar
bir programdaki tüm oluşumlar için yalnızca bir kez kaydedilir . Ruby 2.2'den önce, Symbols
sonsuza 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
Re: bir dize kullanmanın avantajı nedir?
(Ç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.
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ı.