【问题标题】:Why is :key.hash != 'key'.hash in Ruby?为什么 :key.hash != 'key'.hash 在 Ruby 中?
【发布时间】:2012-05-12 00:21:41
【问题描述】:

我现在正在为 Rhodes 移动应用程序框架学习 Ruby,遇到了这个问题:Rhodes 的 HTTP 客户端将 JSON 响应解析为 Ruby 数据结构,例如

puts @params # prints {"body"=>{"results"=>[]}}

由于这里的键“body”是一个字符串,所以我第一次尝试@params[:body] 失败(是nil),而必须是@params['body']。我觉得这是最不幸的。

有人可以解释为什么字符串和符号具有不同的哈希值,即:body.hash != 'body'.hash 在这种情况下?

【问题讨论】:

  • 好吧,因为它们是不同的对象:)

标签: ruby hash dictionary rhodes


【解决方案1】:

符号和字符串有两种不同的用途。

字符串是您熟悉的老朋友:可变且可垃圾回收。每次使用字符串文字或#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"=>[]}}

请注意,它只会触及顶层,不会进入子哈希。

【讨论】:

    【解决方案2】:

    符号和字符串永远不是==

    :foo == 'foo'  # => false
    

    这是一个(非常合理的)设计决定。毕竟,它们有不同的类、方法,一个是可变的,另一个不是,等等......

    因此,他们必须永远不是eql?

    :foo.eql? 'foo'  # => false
    

    不是eql? 的两个对象通常没有相同的哈希,但即使有,哈希查找也会使用hash 然后 eql?。所以你的问题真的是“为什么符号和字符串不是eql?”。

    Rails 使用 HashWithIndifferentAccess 以无差别地访问字符串或符号。

    【讨论】:

    • 这归结为同一个问题,为什么它们不相等?它们不是主要用于同一目的吗?
    • 但是符号不是只用于命名参数和字典键吗?如果是,它们也可以具有与相应字符串相同的哈希值。还有哪些使用符号的地方?
    • @AndiDog:我想,它带来的混乱比解决问题要多得多。混乱是不好的。你的“问题”很容易解决。
    【解决方案3】:

    在 Rails 中,params 哈希实际上是一个 HashWithIndifferentAccess 而不是标准的 ruby​​ 哈希对象。这允许您使用像 'action' 这样的字符串或像 :action 这样的符号来访问内容。

    无论您使用什么,您都将获得相同的结果,但请记住,这仅适用于 HashWithIndifferentAccess 对象。

    复制自:Params hash keys as symbols vs strings

    【讨论】:

    • 您应该在 cmets 中发布此链接。复制粘贴帖子很糟糕。
    • 其实我刚刚获得评论权限...下次会照顾...谢谢Sergio
    猜你喜欢
    • 1970-01-01
    • 2010-09-14
    • 2012-10-30
    • 2019-06-15
    • 2013-03-09
    • 1970-01-01
    • 1970-01-01
    • 2016-06-23
    • 2020-11-28
    相关资源
    最近更新 更多