Jawaban:
TL; DR:
Menggunakan simbol tidak hanya menghemat waktu ketika melakukan perbandingan, tetapi juga menghemat memori, karena mereka hanya disimpan sekali.
Simbol Ruby tidak dapat diubah (tidak dapat diubah), yang membuat pencarian sesuatu menjadi lebih mudah
Jawaban singkat (ish):
Menggunakan simbol tidak hanya menghemat waktu ketika melakukan perbandingan, tetapi juga menghemat memori, karena mereka hanya disimpan sekali.
Simbol di Ruby pada dasarnya adalah "string tidak berubah" .. itu berarti bahwa mereka tidak dapat diubah, dan itu menyiratkan bahwa simbol yang sama ketika direferensikan berulang kali di seluruh kode sumber Anda, selalu disimpan sebagai entitas yang sama, misalnya memiliki id objek yang sama .
String di sisi lain bisa berubah , mereka dapat diubah kapan saja. Ini menyiratkan bahwa Ruby perlu menyimpan setiap string yang Anda sebutkan di seluruh kode sumber Anda di entitas yang terpisah itu, misalnya jika Anda memiliki string "nama" beberapa kali yang disebutkan dalam kode sumber Anda, Ruby perlu menyimpan semua ini dalam objek String yang terpisah, karena mereka mungkin berubah nanti (itulah sifat dari string Ruby).
Jika Anda menggunakan string sebagai kunci hash, Ruby perlu mengevaluasi string dan melihat isinya (dan menghitung fungsi hash pada itu) dan membandingkan hasilnya dengan nilai (hash) dari kunci yang sudah disimpan di hash .
Jika Anda menggunakan simbol sebagai kunci Hash, itu tersirat bahwa itu tidak dapat diubah, jadi Ruby pada dasarnya hanya dapat melakukan perbandingan dari (fungsi hash dari) objek-id terhadap (hash) objek-id dari kunci yang sudah disimpan dalam Hash. (lebih cepat)
Kelemahan: Setiap simbol menggunakan slot di tabel simbol juru bahasa Ruby, yang tidak pernah dirilis. Simbol tidak pernah dikumpulkan dari sampah. Jadi kasus sudut adalah ketika Anda memiliki sejumlah besar simbol (misalnya yang dihasilkan secara otomatis). Dalam hal ini Anda harus mengevaluasi bagaimana ini mempengaruhi ukuran penerjemah Ruby Anda.
Catatan:
Jika Anda melakukan perbandingan string, Ruby dapat membandingkan simbol hanya dengan id objeknya, tanpa harus mengevaluasinya. Itu jauh lebih cepat daripada membandingkan string, yang perlu dievaluasi.
Jika Anda mengakses hash, Ruby selalu menerapkan fungsi hash untuk menghitung "kunci hash" dari kunci apa pun yang Anda gunakan. Anda dapat membayangkan sesuatu seperti hash MD5. Dan kemudian Ruby membandingkan "kunci hash" itu satu sama lain.
Jawaban panjang:
Alasannya adalah efisiensi, dengan beberapa keuntungan lebih dari sebuah String:
O(n)
untuk String dan konstanta untuk Simbol.Selain itu, Ruby 1.9 memperkenalkan sintaks yang disederhanakan hanya untuk hash dengan kunci simbol (misalnya h.merge(foo: 42, bar: 6)
), dan Ruby 2.0 memiliki argumen kata kunci yang hanya berfungsi untuk kunci simbol.
Catatan :
1) Anda mungkin terkejut mengetahui bahwa Ruby memperlakukan String
kunci secara berbeda dari jenis lainnya. Memang:
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
Hanya untuk kunci string, Ruby akan menggunakan salinan beku alih-alih objek itu sendiri.
2) Huruf "b", "a", dan "r" disimpan hanya sekali untuk semua kemunculan :bar
dalam suatu program. Sebelum Ruby 2.2, itu adalah ide yang buruk untuk terus-menerus membuat yang baru Symbols
yang tidak pernah digunakan kembali, karena mereka akan tetap berada di tabel pencarian Simbol global selamanya. Ruby 2.2 akan mengumpulkan sampah, jadi jangan khawatir.
3) Sebenarnya, menghitung hash untuk Simbol tidak memerlukan waktu di Ruby 1.8.x, karena ID objek digunakan secara langsung:
:bar.object_id == :bar.hash # => true in Ruby 1.8.7
Di Ruby 1.9.x, ini telah berubah karena hash berubah dari satu sesi ke sesi lainnya (termasuk yang dari Symbols
):
:bar.hash # => some number that will be different next time Ruby 1.9 is ran
Re: apa keuntungan dibandingkan menggunakan string?
(Sangat) mencari nilai sedikit lebih cepat karena hashing simbol setara dengan hashing integer vs hashing string.
Kerugian: mengkonsumsi slot di tabel simbol program yang tidak pernah dirilis.
Saya akan sangat tertarik dengan tindak lanjut tentang string beku yang diperkenalkan di Ruby 2.x.
Ketika Anda berurusan dengan banyak string yang berasal dari input teks (saya sedang memikirkan params atau payload HTTP, melalui Rack, misalnya), itu cara yang lebih mudah untuk menggunakan string di mana-mana.
Ketika Anda berurusan dengan puluhan dari mereka tetapi mereka tidak pernah berubah (jika itu adalah "kosakata" bisnis Anda), saya suka berpikir bahwa membekukannya dapat membuat perbedaan. Saya belum melakukan benchmark apa pun, tapi saya kira itu akan menutup kinerja simbol.