Qual è la funzione del simbolo in ruby? qual è la differenza tra stringa e simbolo? Perché non è una buona idea creare dinamicamente molti simboli?Perché non è una buona idea creare dinamicamente molti simboli in ruby?
risposta
I simboli sono come stringhe ma sono immutabili - non possono essere modificati.
Vengono solo messi in memoria una volta, rendendoli molto efficienti da usare per cose come le chiavi in hash ma rimangono in memoria fino alla chiusura del programma. Questo li rende un ricordo se li usi male.
Se si creano dinamicamente molti simboli, si assegna molta memoria che non può essere liberata fino alla fine del programma. Si dovrebbe solo creare dinamicamente i simboli (utilizzando string.to_sym
), se sai che sarà:
- necessità di accedere più volte il simbolo
- non hanno bisogno di modificarli
Come ho detto prima, sono utili per cose come hash - dove ti interessa più dell'identità della variabile rispetto al suo valore. I simboli, se usati correttamente, sono un modo leggibile ed efficiente per trasmettere identità.
Spiegherò cosa intendo riguardo l'immutabilità dei simboli RE il tuo commento.
Le stringhe sono come matrici; possono essere modificati sul posto:
12:17:44 ~$ irb
irb(main):001:0> string = "Hello World!"
=> "Hello World!"
irb(main):002:0> string[5] = 'z'
=> "z"
irb(main):003:0> string
=> "HellozWorld!"
irb(main):004:0>
I simboli sono più come numeri; essi non possono essere modificati in atto:
irb(main):011:0> symbol = :Hello_World
=> :Hello_World
irb(main):012:0> symbol[5] = 'z'
NoMethodError: undefined method `[]=' for :Hello_World:Symbol
from (irb):12
from :0
Un simbolo è lo stesso oggetto e lo stesso dotazione di memoria, non importa dove si è usato:
>> :hello.object_id
=> 331068
>> a = :hello
=> :hello
>> a.object_id
=> 331068
>> b = :hello
=> :hello
>> b.object_id
=> 331068
>> a = "hello"
=> "hello"
>> a.object_id
=> 2149256980
>> b = "hello"
=> "hello"
>> b.object_id
=> 2149235120
>> b = "hell" + "o"
Due stringhe che sono 'lo stesso' in quanto contengono gli stessi caratteri potrebbero non fare riferimento alla stessa memoria, che può essere inefficiente se si utilizzano stringhe per, per esempio, hash.
Quindi, i simboli possono essere utili per ridurre il sovraccarico della memoria. Tuttavia - si tratta di una perdita di memoria in attesa di accadere, perché i simboli non possono essere raccolti dopo la creazione. La creazione di migliaia e migliaia di simboli alloca la memoria e non può essere recuperata. Yikes!
Quindi, come utilizzare manualmente la garbage collection? – Ikbear
Non è possibile raccogliere i simboli per quanto ne so. Puoi avviare la garbage collection in qualsiasi momento con 'GC.start'. Ecco un buon articolo sull'argomento: http://viewsourcecode.org/why/hacking/theFullyUpturnedBin.html – stef
ok, grazie per il tuo aiuto! – Ikbear
Può essere particolarmente difficile creare simboli dall'input dell'utente senza convalidare l'input rispetto a una sorta di white-list (ad esempio, per i parametri della stringa di query in RoR). Se l'input dell'utente viene convertito in simboli senza convalida, un utente malintenzionato può far consumare grandi quantità di memoria che non sarà mai raccolta.
Bad (un simbolo si crea indipendentemente input da parte dell'utente):
name = params[:name].to_sym
Buono (un simbolo viene creato solo se è consentita l'input dell'utente):
whitelist = ['allowed_value', 'another_allowed_value']
raise ArgumentError unless whitelist.include?(params[:name])
name = params[:name].to_sym
Se si utilizza Rubino 2.2.0 o versioni successive, in genere dovrebbe essere OK per creare dinamicamente molti simboli, poiché saranno raccolti in base allo standard Ruby 2.2.0-preview1 announcement, che ha un collegamento a more details about the new symbol GC. Tuttavia, se si passano i simboli dinamici a un tipo di codice che lo converte in un ID (un concetto di implementazione di Ruby interno utilizzato nel codice sorgente C), in tal caso verrà bloccato e non verrà mai raccolta la garbage collection. Non sono sicuro di quanto accade comunemente.
Si può pensare ai simboli come a un nome di qualcosa e alle stringhe (approssimativamente) come a una sequenza di caratteri. In molti casi è possibile utilizzare un simbolo o una stringa oppure è possibile utilizzare una combinazione dei due. I simboli sono immutabili, il che significa che non possono essere modificati dopo la creazione. Il modo in cui i simboli sono implementati, è molto efficace confrontare due simboli per vedere se sono uguali, quindi usarli come chiavi per gli hash dovrebbe essere un po 'più veloce rispetto all'utilizzo di stringhe. I simboli non hanno molto i metodi che fanno le stringhe, come ad esempio quindi dovresti usare to_s
per convertire il simbolo in una stringa prima di chiamare quei metodi.
Potete leggere di più su simboli qui nella documentazione:
Starting Ruby 2.2 e soprattutto Symbols sono automaticamente garbage collection e quindi questo non dovrebbe essere un problema.
Stavi lavorando anche con [EdgeCase Ruby koans] (http://rubykoans.com/)? –