Rails using Symbol vs String as key in params hash

If we 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.

If we 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).

But the thing is in Rails params which is instance of HashWithIndifferentAccess , if we write params[:some_key] it converts :some_key to 'some_key' and then it tries to look for the key in params hash. line 159

 def convert_key(key)
    key.kind_of?(Symbol) ? key.to_s : key
  end

so if the lookup is slow with String as key in Hash, why does HashWithIndifferentAccess converts symbol key to string.


The reason used to be security. It's no longer relevant in Ruby 2.2 or later.

Before Ruby 2.2 symbols were not garbage collected. This means that once a symbol was created via a literal ( :my_symbol ) or #to_sym it would be around forever.

If Rails used symbols instead of strings then it would create symbols corresponding to names of params in a request. An attacker could send requests with params named param1 , param2 , ... and exhaust server memory by making the app allocate hundreds of thousands of symbols.

It's no longer the case in Ruby 2.2 or later


:symbol.to_s will always create a new instance string, whereas, "string".to_sym will always produce same symbol.

p "string".to_sym.object_id
#=> 272028
p "string".to_sym.object_id
#=> 272028

p :symbol.to_sym.to_s.object_id
#=>70127441809260
p :symbol.to_sym.to_s.object_id
#=>70127441809160

Hence, it seems that designers of the class store the keys as strings to avoid unnecessary creation of strings during access, especially if one is using hash.keys method (it returns keys as strings).

链接地址: http://www.djcxy.com/p/91814.html

上一篇: 如何证明C#中字符串的不可变性?

下一篇: Rails使用Symbol vs String作为params散列中的键