Ruby数组和nil guard

时间:2016-06-04 17:23:33

标签: arrays ruby multidimensional-array

我有以下代码

class Room
  attr_reader :content, :descr
  def initialize
    @content     = get_content
    @descr       = get_description
  end

  def get_content
    ['errors', 'bugs', 'syntax problems'].sample
  end

  def get_description
    "This room has #{self.content}"
  end
end

@rooms = Array.new(3, Array.new(3))
@rooms[1][1] ||= Room.new 
# => #<Room:0x68985d8 @content="errors", @descr="This room has errors">

p @rooms # =>
#[[nil, #<Room:0x68985d8 @content="errors", @descr="This room has errors">, nil],
# [nil, #<Room:0x68985d8 @content="errors", @descr="This room has errors">, nil],
# [nil, #<Room:0x68985d8 @content="errors", @descr="This room has errors">, nil]]


@rooms = Array.new(3, Array.new(3))
@rooms[1][2] ||= Room.new
# => #<Room:0x6aaab58 @content="bugs", @description="This room contains bugs">

p @rooms # =>
#[[nil, nil, #<Room:0x6aaab58 @content="bugs", @descr="This room has bugs">],
# [nil, nil, #<Room:0x6aaab58 @content="bugs", @descr="This room has bugs">],
# [nil, nil, #<Room:0x6aaab58 @content="bugs", @descr="This room has bugs">]]

它应该在一个地方创建一个新的Room实例(如果它还没有存在),而不是一次在整个列中。它不是在[1][1]或其他任何地方创建所述实例,而是为[0][2][1][2][2][2]设置。

为什么会这样?如何更改它才能正常工作?

1 个答案:

答案 0 :(得分:7)

我最近在这方面遇到了困难,你必须将此行@rooms = Array.new(3, Array.new(3))更改为:

@rooms = Array.new(3) { Array.new(3) }

前者发生的是参数Array.new(3)被评估并创建一个包含3个元素的新数组(我称之为a)。然后,执行Array.new(3, a)创建一个包含3个元素的新数组,所有元素都包含a

a是一个可变对象,因此当您为一列修改它时,所有列都会被修改。

在解决方案中,对每个元素评估块{ Array.new(3) },这就是为什么每列都是不同的数组。