移动应用程序框架学习 Ruby,遇到了这个问题:Rhodes 的 HTTP 客户端将 JSON 响应解析为 Ruby 数据结构,例如
puts @params # prints {"body"=>{"results"=>[]}}
由于这里的键"body"是一个字符串,我的第一次尝试@params[:body]
失败(nil
(,而是必须@params['body']
。我觉得这是最不幸的。
有人可以解释为什么字符串和符号具有不同的哈希值的基本原理,即 在这种情况下:body.hash != 'body'.hash
?
符号和字符串有两个不同的用途。
字符串是你熟悉的好朋友:可变和垃圾收集。每次使用字符串文本或#to_s
方法时,都会创建一个新字符串。您可以使用字符串来构建HTML标记,将文本输出到屏幕等等。
另一方面,符号是不同的。每个符号只存在于一个实例中,并且它始终存在(即,它不是垃圾收集的(。因此,您应该非常小心地制作新符号(String#to_sym
和:''
文字(。这些属性使它们成为命名事物的良好候选项。例如,在宏(如 attr_reader :foo
(中使用符号是惯用的。
如果您从外部源获取哈希(例如,您反序列化了 JSON 响应(,并且想要使用符号来访问其元素,那么您可以使用 HashWithIndifferentAccess(如其他人指出的那样(,或者从 ActiveSupport 调用帮助程序方法:
require 'active_support/core_ext'
h = {"body"=>{"results"=>[]}}
h.symbolize_keys # => {:body=>{"results"=>[]}}
h.stringify_keys # => {"body"=>{"results"=>[]}}
请注意,它只会触及顶层,不会进入子哈希。
符号和字符串永远不会==
:
:foo == 'foo' # => false
这是一个(非常合理的(设计决策。毕竟,它们有不同的类、方法,一个是可变的,另一个不是,等等......
因此,它们必须永远不eql?
:
:foo.eql? 'foo' # => false
两个未eql?
的对象通常不具有相同的哈希,但即使它们具有相同的哈希,哈希查找也会使用 hash
然后eql?
。所以你的问题实际上是"为什么符号和字符串不eql?
"。
Rails 使用HashWithIndifferentAccess
,通过字符串或符号无动于衷地访问。
在 Rails 中,params hash 实际上是一个 HashWithIndifferentAccess 而不是一个标准的 ruby Hash 对象。这允许您使用像"action"这样的字符串或像:action这样的符号来访问内容。
无论您使用什么,您都会得到相同的结果,但请记住,这仅适用于 HashWithIndifferentAccess 对象。
复制自:参数哈希键作为符号与字符串