代码之家  ›  专栏  ›  技术社区  ›  Mladen Jablanović

Ruby方法数组<<不更新哈希中的数组

  •  14
  • Mladen Jablanović  · 技术社区  · 14 年前

    灵感来自 How can I marshal a hash with arrays? 我想知道为什么 Array#<< 在以下代码中无法正常工作:

    h = Hash.new{Array.new}
    #=> {}
    h[0]
    #=> []
    h[0] << 'a'
    #=> ["a"]
    h[0]
    #=> [] # why?!
    h[0] += ['a']
    #=> ["a"]
    h[0]
    #=> ["a"] # as expected
    

    这和 << 就地更改数组,同时 Array#+ 创建新实例?

    3 回复  |  直到 13 年前
        1
  •  33
  •   Jörg W Mittag    14 年前

    如果您创建一个 Hash 使用的块形式 Hash.new ,每次尝试访问实际上不存在的元素时都会执行该块。那么,让我们看看会发生什么:

    h = Hash.new { [] }
    h[0] << 'a'
    

    这里首先要计算的是表达式

    h[0]
    

    当它被评估时会发生什么?好吧,这个街区开始运行:

    []
    

    这并不令人兴奋:块只是创建一个空数组并返回它。它什么都不做。尤其是,它不会改变 h 以任何方式: H 仍然是空的。

    接下来,信息 << 只有一个论点 'a' 发送到的结果 h[0] 这是块的结果,它只是一个空数组:

    [] << 'a'
    

    这是做什么的?它添加了元素 “A” 到一个空数组,但是由于数组实际上没有被分配给任何变量,所以它会立即被垃圾收集并消失。

    现在,如果你评估 H〔0〕 再一次:

    h[0] # => []
    

    H 仍然 空的,因为没有任何分配给它,因此键 0 仍然不存在,这意味着块将运行 再一次 也就是说 再一次 返回空数组(但请注意,它是一个全新的, 不同的 立即清空数组)。

    h[0] += ['a']
    

    这里发生了什么?首先,运算符赋值被减为

    h[0] = h[0] + ['a']
    

    现在, H〔0〕 正确的 侧面被评估。它会返回什么?我们已经讨论过了: H〔0〕 不存在,因此块运行,块返回空数组。同样,这是一个全新的, 第三的 立即清空数组。此空数组将发送消息 + 有了争论 ['a'] 使它返回 另一个 新数组,即数组 [ A ] . 然后将此数组分配给 H〔0〕 .

    最后,在这一点上:

    h[0] # => ['a']
    

    现在你有了 最后 把东西放进去 H〔0〕 所以,很明显,你把你放进去的东西拿出来。

    所以,为了回答你可能有的问题,你为什么不把你放进去的东西拿出来呢?你 没有 把任何东西放在第一位!

    如果你真的想 分配 对于块内的散列,必须将其分配给块内的散列:

    h = Hash.new {|this_hash, nonexistent_key| this_hash[nonexistent_key] = [] }
    h[0] << 'a'
    h[0] # => ['a']
    

    实际上,如果您查看所涉及对象的标识,就很容易看到代码示例中发生了什么。你每次打电话都能看到 H〔0〕 ,你得到一个 不同的 数组。

        2
  •  3
  •   Arkku    13 年前

    代码中的问题是 h[0] << 'a' 生成一个新数组,并在使用 h[0] ,但不会将修改后的数组存储在 << 'a' 因为没有任务。

    同时 h[0] += ['a'] 因为它相当于 h[0] = h[0] + ['a'] . 这是任务( []= )这就不同了。

    第一种情况可能看起来很混乱,但是当您只想从哈希中接收一些不变的默认元素(当找不到键时)时,这是很有用的。否则,只需索引散列就可以用大量未使用的值填充散列。

        3
  •  0
  •   fl00r    14 年前
    h = Hash.new{ |a,b| a[b] = Array.new }
    h[0] << "hello world"
    #=> ["hello world"]
    h[0]
    #=> ["hello world"]