为什么数组没有在Ruby中修改?

时间:2014-11-11 04:15:50

标签: ruby arrays hash

我在IRB上尝试了几行代码,然后我发现我无法修改从Hash返回的新数组作为默认值。以下是IRB会话,更详细地显示了我的情况:

a = Hash.new { Array.new }
#=> {}
a[2]
#=> []
a[2].push '2'
#=> ["2"]
a[2]
#=> []
a[2] = []
#=> []
a[2].push '2'
#=> ["2"]
a
#=> {2=>["2"]}
a[2].push '2'
#=> ["2", "2"]
a
#=> {2=>["2", "2"]}

为什么我无法修改不存在的密钥的默认值?

3 个答案:

答案 0 :(得分:2)

Hash#new的块形式如下所示:

b = Hash.new {|hash, key| hash[key] = Array.new}
#=> {}
b[2]
#=> []
b[2].push('2')
#=> ["2"]
b[2]
#=> ["2"]
b[3]
#=> []
b[3].push('3')
#=> ["3"]
b[3]
#=> ["3"]

答案 1 :(得分:2)

Hash.new {|hash, key| block } → new_hash。它说:

  

如果指定了一个块,则将使用哈希对象调用它   键,应该返回默认值。这是街区   如果需要,有责任将值存储在哈希值中。

这意味着您必须创建一个块,用于存储在创建新值或更新现有值时传递给哈希值的键值。因为,您的哈希定义不存储它:

a = Hash.new { Array.new }

无论你多少次尝试这样做,你都会失去价值:

a[2].push '2' #=> ["2"]
p a #=> {}

您正在做的是然后定义一个具有默认值的键:

a[2] = []

然后推送值:

a[2].push #=> ["2"]
p a #=> {2 => ["2"]}

对于这种情况,还有另一种方法可以将块定义为:

a = Hash.new { |h, k| h[k] = Array.new }

或:

a = Hash.new { |h, k| h[k] = [] }

如果您看到上面的块,它会说:键的默认值将是一个空数组,如果有任何对象被推入其中:

a[2].push '2' #=> ["2"]

它会将该对象存储到该数组中:

p a #=> {2=>["2"]}

答案 2 :(得分:2)

使用时没有问题:

a = Hash.new { Array.new }

如果我执行a[2],它将返回[],因为它是默认值。它只是告诉我它是什么,仅此而已。

因为默认值是作为块给出的,所以每次调用a[x]时,默认值都是一个新的空数组。要理解的重要一点是,它只是一个空数组,不以任何方式与哈希a绑定。也就是说,a[2]只回答问题,"什么是默认值?&#34 ;;它没有做任何事情。 (如其他答案所示,如果块的编写方式不同,可以在返回默认值之前完成各种奇妙的事情。)

请注意,Hash.new { Array.new }Hash.new { [] }Hash.new { |h,k| Array.new }都是等效的。

要将密钥2添加到aa[2]必须是左值。稍后您将在示例中使用它:

a[2] = []

但如果你这样做,就没有必要设置默认值。您要做的是将a[2]设置为等于默认值:

a[2] = a[2]

(注意,如果在这种情况下,块的返回值不依赖于键,则上面的行等同于:

a[2] = a[123456]

如果没有密钥123456。)

这会将键值对2=>[]添加到哈希中,所以现在

a[2].push 2
a[2].push 3
a #=> {2=>[2, 3]}

然而,更有意义的是,只需一步即可:

a[2] = a[2].push 2

如果a没有键2,则相等右侧的a[2]将等于空数组的默认值,2将被推送到它和键2的值将设置为[2]

如果a已有密钥2,请说a[2] = [3,4,5],右侧的a[2]将为[3,4,5]2将被推送在a上(如果它没有2以外的其他键)将是:

a #=> {2=>[3,4,5,2]]}