A lot of times people use symbols as keys in a Ruby hash.
很多时候人们在Ruby散列中使用符号作为键。
What's the advantage over using a string?
使用字符串有什么好处?
E.g.:
例如:
hash[:name]
vs.
vs。
hash['name']
4 个解决方案
#1
200
Short answer:
简短的回答:
Using symbols not only saves time when doing comparisons, but also saves memory, because they are only stored once.
使用符号不仅可以节省进行比较的时间,而且还可以节省内存,因为它们只存储一次。
Symbols in Ruby are basically "immutable strings" .. that means that they can not be changed, and it implies that the same symbol when referenced many times throughout your source code, is always stored as the same entity, e.g. has the same object id.
Ruby中的符号基本上是“不可变的字符串”。这意味着它们不能被修改,这意味着当在整个源代码中多次引用同一个符号时,它总是被存储为相同的实体,例如,具有相同的对象id。
Strings on the other hand are mutable, they can be changed anytime. This implies that Ruby needs to store each string you mention throughout your source code in it's separate entity, e.g. if you have a string "name" multiple times mentioned in your source code, Ruby needs to store these all in separate String objects, because they might change later on (that's the nature of a Ruby string).
另一方面,字符串是可变的,它们可以随时改变。这意味着Ruby需要存储每个字符串你提到在您的源代码中是独立的实体,例如,如果你有一个字符串“name”多次提到你的源代码,Ruby需要这些都存储在单独的字符串对象,因为他们以后可能会改变(这是一个Ruby字符串)的性质。
If you use a string as a Hash key, Ruby needs to evaluate the string and look at it's contents (and compute a hash function on that) and compare the result against the (hashed) values of the keys which are already stored in the Hash.
如果使用字符串作为散列键,Ruby需要计算字符串的值并查看它的内容(并在其上计算一个散列函数),并将结果与已经存储在散列中的键的(散列)值进行比较。
If you use a symbol as a Hash key, it's implicit that it's immutable, so Ruby can basically just do a comparison of the (hash function of the) object-id against the (hashed) object-ids of keys which are already stored in the Hash. (much faster)
如果您将符号用作散列键,那么它是不可变的,因此Ruby基本上可以将对象id的(散列函数)与已经存储在散列中的键的(散列)对象id进行比较。(更快)
Downside: Each symbol consumes a slot in the Ruby interpreter's symbol-table, which is never released. Symbols are never garbage-collected. So a corner-case is when you have a large number of symbols (e.g. auto-generated ones). In that case you should evaluate how this affects the size of your Ruby interpreter.
缺点:每个符号都使用Ruby解释器的符号表中的一个槽,这个槽永远不会被释放。符号不会被垃圾收集。因此,当你有大量的符号(例如自动生成的符号)时,就会出现这种情况。在这种情况下,您应该评估这对Ruby解释器大小的影响。
Notes:
注:
If you do string comparisons, Ruby can compare symbols just by their object ids, without having to evaluate them. That's much faster than comparing strings, which need to be evaluated.
如果您进行字符串比较,Ruby可以仅根据它们的对象id进行比较,而不必对它们进行计算。这比比较需要计算的字符串要快得多。
If you access a hash, Ruby always applies a hash-function to compute a "hash-key" from whatever key you use. You can imagine something like an MD5-hash. And then Ruby compares those "hashed keys" against each other.
如果您访问一个散列,Ruby总是应用一个散列函数来从您使用的任何键计算一个“散列键”。你可以想象一些类似md5哈希的东西。然后Ruby将这些“散列键”进行比较。
Long answer:
长一点的回答:
http://www.reactive.io/tips/2009/01/11/the-difference-between-ruby-symbols-and-strings
http://www.reactive.io/tips/2009/01/11/the-difference-between-ruby-symbols-and-strings
http://www.randomhacks.net/articles/2007/01/20/13-ways-of-looking-at-a-ruby-symbol
http://www.randomhacks.net/articles/2007/01/20/13-ways-of-looking-at-a-ruby-symbol
#2
21
The reason is efficiency, with multiple gains over a String:
原因是效率,一个字符串的多重增益:
- Symbols are immutable, so the question "what happens if the key changes?" doesn't need to be asked.
- 符号是不可变的,所以不需要问“如果键改变了会发生什么?”
- Strings are duplicated in your code and will typically take more space in memory.
- 字符串在代码中被复制,并且通常在内存中占用更多的空间。
- Hash lookups must compute the hash of the keys to compare them. This is
O(n)
for Strings and constant for Symbols. - 哈希查找必须计算键的哈希值来比较它们。这是O(n)表示字符串,常数表示符号。
Moreover, Ruby 1.9 introduced a simplified syntax just for hash with symbols keys (e.g. h.merge(foo: 42, bar: 6)
), and Ruby 2.0 has keyword arguments that work only for symbol keys.
此外,Ruby 1.9引入了一种简化的语法,只对带有符号键(例如h)的哈希进行语法处理。merge(foo: 42, bar: 6), Ruby 2.0有只用于符号键的关键字参数。
Notes:
注:
1) You might be surprised to learn that Ruby treats String
keys differently than any other type. Indeed:
1)您可能会惊讶地发现Ruby对待字符串键的方式与其他类型不同。事实上:
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
For string keys only, Ruby will use a frozen copy instead of the object itself.
对于字符串键,Ruby将使用一个冻结的副本而不是对象本身。
2) The letters "b", "a", and "r" are stored only once for all occurrences of :bar
in a program. Before Ruby 2.2, it was a bad idea to constantly create new Symbols
that were never reused, as they would remain in the global Symbol lookup table forever. Ruby 2.2 will garbage collect them, so no worries.
2)字母“b”、“a”和“r”只存储一次,用于所有出现的:程序中的bar。在Ruby 2.2之前,不断地创建从未被重用的新符号是一个坏主意,因为它们将永远留在全局符号查找表中。Ruby 2.2将垃圾收集它们,所以不用担心。
3) Actually, computing the hash for a Symbol didn't take any time in Ruby 1.8.x, as the object ID was used directly:
3)实际上,在Ruby 1.8中计算符号的哈希值并没有花费任何时间。x,由于直接使用对象ID:
:bar.object_id == :bar.hash # => true in Ruby 1.8.7
In Ruby 1.9.x, this has changed as hashes change from one session to another (including those of Symbols
):
在Ruby 1.9。x,当散列从一个会话更改为另一个会话(包括符号)时,这个值已经更改:
:bar.hash # => some number that will be different next time Ruby 1.9 is ran
#3
6
Re: what's the advantage over using a string?
Re:使用字符串的优点是什么?
- Styling: its the Ruby-way
- 样式:ruby方式
-
(Very) slightly faster value look ups since hashing a symbol is equivalent to hashing an integer vs hashing a string.
(非常)稍微快一点的值查找,因为哈希一个符号等价于哈希一个整数和哈希一个字符串。
-
Disadvantage: consumes a slot in the program's symbol table that is never released.
缺点:在程序的符号表中消耗一个没有释放的槽。
#4
0
I'd be very interested in a follow-up regarding frozen strings introduced in Ruby 2.x.
我对Ruby 2.x中引入的冻结字符串的后续操作非常感兴趣。
When you deal with numerous strings coming from a text input (I'm thinking of HTTP params or payload, through Rack, for example), it's way easier to use strings everywhere.
当您处理来自文本输入的众多字符串时(例如,我考虑的是HTTP params或有效负载,例如通过Rack),在任何地方使用字符串都比较容易。
When you deal with dozens of them but they never change (if they're your business "vocabulary"), I like to think that freezing them can make a difference. I haven't done any benchmark yet, but I guess it would be close the symbols performance.
当你处理了几十个这样的问题,但它们永远不会改变(如果它们是你的商业“词汇”的话),我喜欢认为把它们冷冻起来会有很大的不同。我还没有做任何基准测试,但我想它会接近符号性能。
#1
200
Short answer:
简短的回答:
Using symbols not only saves time when doing comparisons, but also saves memory, because they are only stored once.
使用符号不仅可以节省进行比较的时间,而且还可以节省内存,因为它们只存储一次。
Symbols in Ruby are basically "immutable strings" .. that means that they can not be changed, and it implies that the same symbol when referenced many times throughout your source code, is always stored as the same entity, e.g. has the same object id.
Ruby中的符号基本上是“不可变的字符串”。这意味着它们不能被修改,这意味着当在整个源代码中多次引用同一个符号时,它总是被存储为相同的实体,例如,具有相同的对象id。
Strings on the other hand are mutable, they can be changed anytime. This implies that Ruby needs to store each string you mention throughout your source code in it's separate entity, e.g. if you have a string "name" multiple times mentioned in your source code, Ruby needs to store these all in separate String objects, because they might change later on (that's the nature of a Ruby string).
另一方面,字符串是可变的,它们可以随时改变。这意味着Ruby需要存储每个字符串你提到在您的源代码中是独立的实体,例如,如果你有一个字符串“name”多次提到你的源代码,Ruby需要这些都存储在单独的字符串对象,因为他们以后可能会改变(这是一个Ruby字符串)的性质。
If you use a string as a Hash key, Ruby needs to evaluate the string and look at it's contents (and compute a hash function on that) and compare the result against the (hashed) values of the keys which are already stored in the Hash.
如果使用字符串作为散列键,Ruby需要计算字符串的值并查看它的内容(并在其上计算一个散列函数),并将结果与已经存储在散列中的键的(散列)值进行比较。
If you use a symbol as a Hash key, it's implicit that it's immutable, so Ruby can basically just do a comparison of the (hash function of the) object-id against the (hashed) object-ids of keys which are already stored in the Hash. (much faster)
如果您将符号用作散列键,那么它是不可变的,因此Ruby基本上可以将对象id的(散列函数)与已经存储在散列中的键的(散列)对象id进行比较。(更快)
Downside: Each symbol consumes a slot in the Ruby interpreter's symbol-table, which is never released. Symbols are never garbage-collected. So a corner-case is when you have a large number of symbols (e.g. auto-generated ones). In that case you should evaluate how this affects the size of your Ruby interpreter.
缺点:每个符号都使用Ruby解释器的符号表中的一个槽,这个槽永远不会被释放。符号不会被垃圾收集。因此,当你有大量的符号(例如自动生成的符号)时,就会出现这种情况。在这种情况下,您应该评估这对Ruby解释器大小的影响。
Notes:
注:
If you do string comparisons, Ruby can compare symbols just by their object ids, without having to evaluate them. That's much faster than comparing strings, which need to be evaluated.
如果您进行字符串比较,Ruby可以仅根据它们的对象id进行比较,而不必对它们进行计算。这比比较需要计算的字符串要快得多。
If you access a hash, Ruby always applies a hash-function to compute a "hash-key" from whatever key you use. You can imagine something like an MD5-hash. And then Ruby compares those "hashed keys" against each other.
如果您访问一个散列,Ruby总是应用一个散列函数来从您使用的任何键计算一个“散列键”。你可以想象一些类似md5哈希的东西。然后Ruby将这些“散列键”进行比较。
Long answer:
长一点的回答:
http://www.reactive.io/tips/2009/01/11/the-difference-between-ruby-symbols-and-strings
http://www.reactive.io/tips/2009/01/11/the-difference-between-ruby-symbols-and-strings
http://www.randomhacks.net/articles/2007/01/20/13-ways-of-looking-at-a-ruby-symbol
http://www.randomhacks.net/articles/2007/01/20/13-ways-of-looking-at-a-ruby-symbol
#2
21
The reason is efficiency, with multiple gains over a String:
原因是效率,一个字符串的多重增益:
- Symbols are immutable, so the question "what happens if the key changes?" doesn't need to be asked.
- 符号是不可变的,所以不需要问“如果键改变了会发生什么?”
- Strings are duplicated in your code and will typically take more space in memory.
- 字符串在代码中被复制,并且通常在内存中占用更多的空间。
- Hash lookups must compute the hash of the keys to compare them. This is
O(n)
for Strings and constant for Symbols. - 哈希查找必须计算键的哈希值来比较它们。这是O(n)表示字符串,常数表示符号。
Moreover, Ruby 1.9 introduced a simplified syntax just for hash with symbols keys (e.g. h.merge(foo: 42, bar: 6)
), and Ruby 2.0 has keyword arguments that work only for symbol keys.
此外,Ruby 1.9引入了一种简化的语法,只对带有符号键(例如h)的哈希进行语法处理。merge(foo: 42, bar: 6), Ruby 2.0有只用于符号键的关键字参数。
Notes:
注:
1) You might be surprised to learn that Ruby treats String
keys differently than any other type. Indeed:
1)您可能会惊讶地发现Ruby对待字符串键的方式与其他类型不同。事实上:
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
For string keys only, Ruby will use a frozen copy instead of the object itself.
对于字符串键,Ruby将使用一个冻结的副本而不是对象本身。
2) The letters "b", "a", and "r" are stored only once for all occurrences of :bar
in a program. Before Ruby 2.2, it was a bad idea to constantly create new Symbols
that were never reused, as they would remain in the global Symbol lookup table forever. Ruby 2.2 will garbage collect them, so no worries.
2)字母“b”、“a”和“r”只存储一次,用于所有出现的:程序中的bar。在Ruby 2.2之前,不断地创建从未被重用的新符号是一个坏主意,因为它们将永远留在全局符号查找表中。Ruby 2.2将垃圾收集它们,所以不用担心。
3) Actually, computing the hash for a Symbol didn't take any time in Ruby 1.8.x, as the object ID was used directly:
3)实际上,在Ruby 1.8中计算符号的哈希值并没有花费任何时间。x,由于直接使用对象ID:
:bar.object_id == :bar.hash # => true in Ruby 1.8.7
In Ruby 1.9.x, this has changed as hashes change from one session to another (including those of Symbols
):
在Ruby 1.9。x,当散列从一个会话更改为另一个会话(包括符号)时,这个值已经更改:
:bar.hash # => some number that will be different next time Ruby 1.9 is ran
#3
6
Re: what's the advantage over using a string?
Re:使用字符串的优点是什么?
- Styling: its the Ruby-way
- 样式:ruby方式
-
(Very) slightly faster value look ups since hashing a symbol is equivalent to hashing an integer vs hashing a string.
(非常)稍微快一点的值查找,因为哈希一个符号等价于哈希一个整数和哈希一个字符串。
-
Disadvantage: consumes a slot in the program's symbol table that is never released.
缺点:在程序的符号表中消耗一个没有释放的槽。
#4
0
I'd be very interested in a follow-up regarding frozen strings introduced in Ruby 2.x.
我对Ruby 2.x中引入的冻结字符串的后续操作非常感兴趣。
When you deal with numerous strings coming from a text input (I'm thinking of HTTP params or payload, through Rack, for example), it's way easier to use strings everywhere.
当您处理来自文本输入的众多字符串时(例如,我考虑的是HTTP params或有效负载,例如通过Rack),在任何地方使用字符串都比较容易。
When you deal with dozens of them but they never change (if they're your business "vocabulary"), I like to think that freezing them can make a difference. I haven't done any benchmark yet, but I guess it would be close the symbols performance.
当你处理了几十个这样的问题,但它们永远不会改变(如果它们是你的商业“词汇”的话),我喜欢认为把它们冷冻起来会有很大的不同。我还没有做任何基准测试,但我想它会接近符号性能。