Jika ada setidaknya dua contoh dari string yang sama dalam skrip saya, haruskah saya menggunakan simbol?
Jika ada setidaknya dua contoh dari string yang sama dalam skrip saya, haruskah saya menggunakan simbol?
Jawaban:
Aturan praktis yang sederhana adalah menggunakan simbol setiap kali Anda membutuhkan pengenal internal. Untuk Ruby <2.2 hanya gunakan simbol jika tidak dibuat secara dinamis, untuk menghindari kebocoran memori.
Satu-satunya alasan untuk tidak menggunakannya untuk pengenal yang dibuat secara dinamis adalah karena masalah memori.
Pertanyaan ini sangat umum karena banyak bahasa pemrograman tidak memiliki simbol, hanya string, dan dengan demikian string juga digunakan sebagai pengenal dalam kode Anda. Anda harus mengkhawatirkan tentang simbol-simbol apa yang dimaksudkan untuk menjadi , tidak hanya ketika Anda harus menggunakan simbol-simbol . Simbol dimaksudkan sebagai pengenal. Jika Anda mengikuti filosofi ini, kemungkinan besar Anda akan melakukan hal-hal dengan benar.
Ada beberapa perbedaan antara penerapan simbol dan string. Hal terpenting tentang simbol adalah bahwa simbol itu tidak dapat diubah . Ini berarti bahwa nilai mereka tidak akan pernah berubah. Karenanya, simbol dibuat lebih cepat daripada string dan beberapa operasi seperti membandingkan dua simbol juga lebih cepat.
Fakta bahwa sebuah simbol tidak dapat diubah memungkinkan Ruby untuk menggunakan objek yang sama setiap kali Anda mereferensikan simbol tersebut, sehingga menghemat memori. Jadi setiap kali interpreter membacanya, interpreter :my_key
dapat mengambilnya dari memori alih-alih membuat instance lagi. Ini lebih murah daripada menginisialisasi string baru setiap saat.
Anda bisa mendapatkan daftar semua simbol yang sudah dipakai dengan perintah Symbol.all_symbols
:
symbols_count = Symbol.all_symbols.count # all_symbols is an array with all
# instantiated symbols.
a = :one
puts a.object_id
# prints 167778
a = :two
puts a.object_id
# prints 167858
a = :one
puts a.object_id
# prints 167778 again - the same object_id from the first time!
puts Symbol.all_symbols.count - symbols_count
# prints 2, the two objects we created.
Untuk versi Ruby sebelum 2.2, setelah simbol dibuat, memori ini tidak akan pernah bisa bebas lagi . Satu-satunya cara untuk mengosongkan memori adalah dengan memulai ulang aplikasi. Jadi simbol juga menjadi penyebab utama kebocoran memori saat digunakan secara tidak benar. Cara termudah untuk menghasilkan kebocoran memori adalah dengan menggunakan metode to_sym
pada data input pengguna, karena data ini akan selalu berubah, sebagian memori baru akan digunakan selamanya dalam contoh perangkat lunak. Ruby 2.2 memperkenalkan simbol pengumpul sampah , yang membebaskan simbol yang dibuat secara dinamis, sehingga kebocoran memori yang dihasilkan dengan membuat simbol secara dinamis tidak lagi menjadi masalah.
Menjawab pertanyaan Anda:
Apakah benar saya harus menggunakan simbol, bukan string jika ada setidaknya dua string yang sama dalam aplikasi atau skrip saya?
Jika yang Anda cari adalah pengenal untuk digunakan secara internal di kode Anda, Anda harus menggunakan simbol. Jika Anda mencetak keluaran, Anda harus menggunakan string, meskipun muncul lebih dari sekali, bahkan mengalokasikan dua objek berbeda dalam memori.
Berikut alasannya:
@AlanDert: jika saya sering menggunakan sesuatu seperti% input {type:: checkbox} dalam kode haml, apa yang harus saya gunakan sebagai kotak centang?
Saya iya.
@AlanDert: Tetapi untuk mencetak simbol pada halaman html, itu harus diubah menjadi string, bukan? lalu apa gunanya menggunakannya?
Apa jenis inputnya? Pengenal jenis masukan yang ingin Anda gunakan atau sesuatu yang ingin Anda tunjukkan kepada pengguna?
Memang benar bahwa ini akan menjadi kode HTML di beberapa titik, tetapi pada saat Anda menulis baris kode Anda, itu dimaksudkan sebagai pengenal - ini mengidentifikasi jenis bidang input yang Anda butuhkan. Oleh karena itu, ini digunakan berulang kali dalam kode Anda, dan selalu memiliki "string" karakter yang sama dengan pengenal dan tidak akan menghasilkan kebocoran memori.
Karena itu, mengapa kita tidak mengevaluasi data untuk melihat apakah string lebih cepat?
Ini adalah patokan sederhana yang saya buat untuk ini:
require 'benchmark'
require 'haml'
str = Benchmark.measure do
10_000.times do
Haml::Engine.new('%input{type: "checkbox"}').render
end
end.total
sym = Benchmark.measure do
10_000.times do
Haml::Engine.new('%input{type: :checkbox}').render
end
end.total
puts "String: " + str.to_s
puts "Symbol: " + sym.to_s
Tiga keluaran:
# first time
String: 5.14
Symbol: 5.07
#second
String: 5.29
Symbol: 5.050000000000001
#third
String: 4.7700000000000005
Symbol: 4.68
Jadi menggunakan smbol sebenarnya sedikit lebih cepat daripada menggunakan string. Mengapa demikian? Itu tergantung pada cara HAML diimplementasikan. Saya perlu meretas sedikit kode HAML untuk melihatnya, tetapi jika Anda tetap menggunakan simbol dalam konsep pengenal, aplikasi Anda akan lebih cepat dan dapat diandalkan. Saat pertanyaan muncul, ukur dan dapatkan jawaban Anda.
Sederhananya, simbol adalah nama, terdiri dari karakter, tetapi tidak berubah. Sebaliknya, string adalah penampung yang dipesan untuk karakter, yang isinya boleh diubah.
Untuk membandingkan dua string, kita perlu melihat setiap karakter. Untuk dua string dengan panjang N, ini akan membutuhkan perbandingan N + 1 (yang oleh para ilmuwan komputer disebut sebagai "waktu O (N)").
def string_comp str1, str2
return false if str1.length != str2.length
for i in 0...str1.length
return false if str1[i] != str2[i]
end
return true
end
string_comp "foo", "foo"
Tetapi karena setiap kemunculan: foo mengacu pada objek yang sama, kita dapat membandingkan simbol dengan melihat ID objek. Kita dapat melakukan ini dengan satu perbandingan (yang oleh para ilmuwan komputer disebut sebagai "O (1) waktu").
def symbol_comp sym1, sym2
sym1.object_id == sym2.object_id
end
symbol_comp :foo, :foo
Di C ++, kita dapat menggunakan "enumerasi" untuk mewakili keluarga konstanta terkait:
enum BugStatus { OPEN, CLOSED };
BugStatus original_status = OPEN;
BugStatus current_status = CLOSED;
Tetapi karena Ruby adalah bahasa yang dinamis, kami tidak khawatir tentang mendeklarasikan tipe BugStatus, atau melacak nilai-nilai legal. Sebagai gantinya, kami mewakili nilai pencacahan sebagai simbol:
original_status = :open
current_status = :closed
3. Simbol Ruby adalah nama yang konstan dan unik
Di Ruby, kita dapat mengubah konten string:
"foo"[0] = ?b # "boo"
Tapi kita tidak bisa mengubah isi simbol:
:foo[0] = ?b # Raises an error
Saat meneruskan argumen kata kunci ke fungsi Ruby, kami menentukan kata kunci menggunakan simbol:
# Build a URL for 'bug' using Rails.
url_for :controller => 'bug',
:action => 'show',
:id => bug.id
Biasanya, kami akan menggunakan simbol untuk mewakili kunci tabel hash:
options = {}
options[:auto_save] = true
options[:show_comments] = false
Berikut adalah patokan string vs simbol bagus yang saya temukan di codecademy:
require 'benchmark'
string_AZ = Hash[("a".."z").to_a.zip((1..26).to_a)]
symbol_AZ = Hash[(:a..:z).to_a.zip((1..26).to_a)]
string_time = Benchmark.realtime do
1000_000.times { string_AZ["r"] }
end
symbol_time = Benchmark.realtime do
1000_000.times { symbol_AZ[:r] }
end
puts "String time: #{string_time} seconds."
puts "Symbol time: #{symbol_time} seconds."
Outputnya adalah:
String time: 0.21983 seconds.
Symbol time: 0.087873 seconds.
gunakan simbol sebagai pengenal kunci hash
{key: "value"}
simbol memungkinkan Anda memanggil metode dalam urutan yang berbeda
def write (file :, data :, mode: "ascii") # dihapus agar singkat akhir tulis (data: 123, file: "test.txt")
membekukan untuk disimpan sebagai string dan menghemat memori
label = 'My Label'.freeze
/
(setelahstrings
) dari tautan. Ini dia: www.reactive.io/tips/2009/01/11/the-difference-between-ruby- symbol-and-string