为什么散列的字符串键被冻结? [英] Why is a string key for a hash frozen?

查看:92
本文介绍了为什么散列的字符串键被冻结?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

根据规范,使用的字符串作为散列的关键被复制和冻结。其他可变对象似乎没有这样特殊的考虑。例如,使用数组键,以下是可能的。

  a = [0] 
h = {a = > :a}
h.keys.first [0] = 1
h#=> {[1] => :a}
h [[1]]#=>无
h.rehash
h [[1]]#=> :a

另一方面,类似的东西不能用字符串键完成。

  s =a
h = {s => :s}
h.keys.first.upcase! #=> RuntimeError:无法修改冻结字符串

为什么字符串设计为与其他可变对象不同来一个哈希键?有没有这个规范变得有用的用例?这个规范有什么其他的后果?





我实际上有一个用例,其中缺少关于字符串的这种特殊规范可能会有用。也就是说,我用 yaml gem读取了一个手动编写的描述散列的YAML文件。键可能是字符串,我想在原始YAML文件中允许不区分大小写。当我读取一个文件时,我可能会得到一个这样的散列:

  h = {foo=> :foo,Bar=> :小节,BAZ=> :baz} 

我想将这些键标准化为小写字母来获得它:

  h = {foo=> :foo,bar=> :bar,baz=> :baz} 

通过这样做:

  h.keys.each(&::downcase!)

但是,由于上面解释的原因,它返回了一个错误。 简单地说,它只是Ruby试图很好。

/ p>

在哈希中输入密钥时,会使用密钥的哈希方法计算特殊数字。哈希对象使用这个数字来检索密钥。例如,如果你问 h ['a'] 的值是什么,Hash调用 hash 方法字符串'a'并检查它是否存储了该数字的值。当某人(你)突变字符串对象时,问题就出现了,所以字符串'a'现在是别的东西,比如'aa'。哈希不会找到'aa'的哈希数字。

散列的最常见类型是字符串,符号和整数。符号和整数是不可变的,但字符串不是。 Ruby试图通过检查和冻结字符串键来防止上述混淆行为。我想这不是为其他类型完成的,因为可能存在令人讨厌的性能副作用(想想大数组)。

According to the specification, strings that are used as a key to a hash are duplicated and frozen. Other mutable objects do not seem to have such special consideration. For example, with an array key, the following is possible.

a = [0]
h = {a => :a}
h.keys.first[0] = 1
h # => {[1] => :a}
h[[1]] # => nil
h.rehash
h[[1]] # => :a

On the other hand, a similar thing cannot be done with a string key.

s = "a"
h = {s => :s}
h.keys.first.upcase! # => RuntimeError: can't modify frozen String

Why is string designed to be different from other mutable objects when it comes to a hash key? Is there any use case where this specification becomes useful? What other consequences does this specification have?


I actually have a use case where absence of such special specification about strings may be useful. That is, I read with the yaml gem a manually written YAML file that describes a hash. the keys may be strings, and I would like to allow case insensitivity in the original YAML file. When I read a file, I might get a hash like this:

h = {"foo" => :foo, "Bar" => :bar, "BAZ" => :baz}

And I want to normalize the keys to lower case to get this:

h = {"foo" => :foo, "bar" => :bar, "baz" => :baz}

by doing something like this:

h.keys.each(&:downcase!)

but that returns an error for the reason explained above.

解决方案

In short it's just Ruby trying to be nice.

When a key is entered in a Hash, a special number is calculated, using the hash method of the key. The Hash object uses this number to retrieve the key. For instance, if you ask what the value of h['a'] is, the Hash calls the hash method of string 'a' and checks if it has a value stored for that number. The problem arises when someone (you) mutates the string object, so the string 'a' is now something else, let's say 'aa'. The Hash would not find a hash number for 'aa'.

The most common types of keys for hashes are strings, symbols and integers. Symbols and integers are immutable, but strings are not. Ruby tries to protect you from the confusing behaviour described above by dupping and freezing string keys. I guess it's not done for other types because there could be nasty performance side effects (think of large arrays).

这篇关于为什么散列的字符串键被冻结?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆