2011-01-01 10 views

risposta

82

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à:

  1. necessità di accedere più volte il simbolo
  2. 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 
+0

Se un simbolo non viene creato dinamicamente, non può essere modificato? puoi darmi un esempio? – Ikbear

+0

ok, ora è chiaro per me. Grazie! – Ikbear

8

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!

+0

Quindi, come utilizzare manualmente la garbage collection? – Ikbear

+1

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

+0

ok, grazie per il tuo aiuto! – Ikbear

5

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 
1

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:

http://www.ruby-doc.org/core-2.1.3/Symbol.html

Problemi correlati