If there are at least two instances of the same string in my script, should I instead use a symbol?
相关问题
- How to specify memcache server to Rack::Session::M
- Why am I getting a “C compiler cannot create execu
- reference to a method?
- ruby 1.9 wrong file encoding on windows
- gem cleanup shows error: Unable to uninstall bundl
相关文章
- Ruby using wrong version of openssl
- Difference between Thread#run and Thread#wakeup?
- how to call a active record named scope with a str
- “No explicit conversion of Symbol into String” for
- Segmentation fault with ruby 2.0.0p247 leading to
- How to detect if an element exists in Watir
- uninitialized constant Mysql2::Client::SECURE_CONN
- ruby - simplify string multiply concatenation
Put simply, a symbol is a name, composed of characters, but immutable. A string, on the contrary, is an ordered container for characters, whose contents are allowed to change.
Here is a nice strings vs symbols benchmark I found at codecademy:
The output is:
TL;DR
A simple rule of thumb is to use symbols every time you need internal identifiers. For Ruby < 2.2 only use symbols when they aren't generated dynamically, to avoid memory leaks.
Full answer
The only reason not to use them for identifiers that are generated dynamically is because of memory concerns.
This question is very common because many programming languages don't have symbols, only strings, and thus strings are also used as identifiers in your code. You should be worrying about what symbols are meant to be, not only when you should use symbols. Symbols are meant to be identifiers. If you follow this philosophy, chances are that you will do things right.
There are several differences between the implementation of symbols and strings. The most important thing about symbols is that they are immutable. This means that they will never have their value changed. Because of this, symbols are instantiated faster than strings and some operations like comparing two symbols is also faster.
The fact that a symbol is immutable allows Ruby to use the same object every time you reference the symbol, saving memory. So every time the interpreter reads
:my_key
it can take it from memory instead of instantiate it again. This is less expensive than initializing a new string every time.You can get a list all symbols that are already instantiated with the command
Symbol.all_symbols
:For Ruby versions before 2.2, once a symbol is instantiated, this memory will never be free again. The only way to free the memory is restarting the application. So symbols are also a major cause of memory leaks when used incorrectly. The simplest way to generate a memory leak is using the method
to_sym
on user input data, since this data will always change, a new portion of the memory will be used forever in the software instance. Ruby 2.2 introduced the symbol garbage collector, which frees symbols generated dynamically, so the memory leaks generated by creating symbols dynamically it is not a concern any longer.Answering your question:
If what you are looking for is an identifier to be used internally at your code, you should be using symbols. If you are printing output, you should go with strings, even if it appears more than once, even allocating two different objects in memory.
Here's the reasoning:
Use case by @AlanDert
What is the type of an input? An identifier of the type of input you want to use or something you want to show to the user?
It is true that it will become HTML code at some point, but at the moment you are writing that line of your code, it is mean to be an identifier - it identifies what kind of input field you need. Thus, it is used over and over again in your code, and have always the same "string" of characters as the identifier and won't generate a memory leak.
That said, why don't we evaluate the data to see if strings are faster?
This is a simple benchmark I created for this:
Three outputs:
So using smbols is actually a bit faster than using strings. Why is that? It depends on the way HAML is implemented. I would need to hack a bit on HAML code to see, but if you keep using symbols in the concept of an identifier, your application will be faster and reliable. When questions strike, benchmark it and get your answers.
To compare two strings, we potentially need to look at every character. For two strings of length N, this will require N+1 comparisons (which computer scientists refer to as "O(N) time").
But since every appearance of :foo refers to the same object, we can compare symbols by looking at object IDs. We can do this with a single comparison (which computer scientists refer to as "O(1) time").
In C++, we can use "enumerations" to represent families of related constants:
But because Ruby is a dynamic language, we don't worry about declaring a BugStatus type, or keeping track of the legal values. Instead, we represent the enumeration values as symbols:
3.A Ruby symbol is a constant, unique name
In Ruby, we can change the contents of a string:
But we can't change the contents of a symbol:
When passing keyword arguments to a Ruby function, we specify the keywords using symbols:
Typically, we'll use symbols to represent the keys of a hash table:
use symbols as hash key identifiers
{key: "value"}
symbols allow you to call the method in a different order
freeze to keep as a string and save memory
label = 'My Label'.freeze