Ruby的.push和<<之间的区别

Ser*_*gey -1 ruby

这是推送的一个例子:

@connections = Hash.new []
@connections[1] = @connections[1].push(2)
puts @connections # => {1=>[2]}
Run Code Online (Sandbox Code Playgroud)

这是<<的一个例子

@connections = Hash.new []
@connections[1] << 2
puts @connections # => {}
Run Code Online (Sandbox Code Playgroud)

由于某种原因,输出(@connections)是不同的,但为什么呢?我猜它与Ruby对象模型有关?

也许新的哈希对象[]每次都在创建,但是没有保存?但为什么?

sep*_*p2k 9

在你的代码的区别是不是<<push,这是一个事实,即你在一个情况下重新分配,并在其他没有.以下两段代码是等效的:

@connections = Hash.new []
@connections[1] = @connections[1].push(2)
puts @connections # => {1=>[2]}

@connections = Hash.new []
@connections[1] = (@connections[1] << 2)
puts @connections # => {1=>[2]}
Run Code Online (Sandbox Code Playgroud)

这两个是:

@connections = Hash.new []
@connections[1].push(2)
puts @connections # => {}

@connections = Hash.new []
@connections[1] << 2
puts @connections # => {}
Run Code Online (Sandbox Code Playgroud)

重新分配在这里产生影响的原因是访问默认值,不会自动为哈希添加条目.也就是说,如果你有h = Hash.new(0),然后你做p h[0],你将打印0,但值h仍然是{}(不{0 => 0}),因为0没有添加到哈希.如果这样做h[0] += 1,这将调用[]=散列上的方法,并实际为其添加0的条目,所以h变为{0 => 1}.

因此,当@connections[1] << 2您使用代码时,您将获得默认数组并对其执行<<,但您不会存储任何内容@connections,因此它会保留{}.当你这样做@connections[i] = @connections[i].push(2)或者@connections[i] = (@connections[i] << 2)你正在调用时[]=,所以条目被添加到哈希中.


但是你应该注意,哈希每次都会返回对同一个数组的引用,所以即使你确实将条目添加到哈希中,一旦你添加了多个条目,它仍然可能不会像你期望的那样(因为所有条目都是如此)引用相同的数组):

@connections = Hash.new []
@connections[1] = @connections[1].push(2)
@connections[2] = @connections[2].push(42)
puts @connections # => {1 => [2, 42], 2 => [2, 42]}
Run Code Online (Sandbox Code Playgroud)

您真正想要的是一个哈希值,每次访问新密钥时都会返回对新数组的引用,并在发生这种情况时自动为新数组添加一个条目.要做到这一点,你可以使用这样的块形式Hash.new:

@connections = Hash.new do |h, k|
  h[k] = []
end
@connections[1].push(2)
@connections[2].push(42)
puts @connections # => {1 => [2], 2 => [42]}
Run Code Online (Sandbox Code Playgroud)