为什么在括号方法中索引self而不是实例变量

时间:2018-05-23 01:22:00

标签: ruby

我有:

class Thing
  def initialize
    @array = [[0, 0, 0], [1, 1, 1]]
  end
end

thing = Thing.new

访问@array中元素的常规方法是使用[],如下所示:

@array[0][1] # => 0

我正在尝试覆盖[],以便得到这样的结果:

position_array = [0, 1]
@array[position_array] # => 0

这是我的尝试:

class Thing
  def [](position_array)
    index_row, index_col = position_array
    @array[index_row][index_col]
  end

  def get_value(position_array)
    @array[position_array]           # doesn't work
    # self[position_array]           # does work
  end
end

thing.get_value([0, 1])
# >> 'get_value': no implicit conversion of Array into Integer (TypeError)

为什么我需要索引Thing对象以索引@array

2 个答案:

答案 0 :(得分:1)

可以使用前置方法通过鸭子输入传递给[]方法的参数来非侵入性地覆盖Array中的[]方法,然后调用原来的,如果它不是你的期望。那么你根本不需要Thing个对象。

module MyArrayExtension
  def [] (*param)
    if param.size == 2
      row, col = param
      raise ArgumentError, 'Row must be an integer' if row.class != Integer
      raise ArgumentError, 'Column must be an integer' if col.class != Integer
      raise ArgumentError, "Element at row #{row} is not an array" if self[row].class != Array
      self[row][col]
    else
      super
    end
  end
end

class Array
  prepend MyArrayExtension
end

thing = [[1,2,3],[4,5,6]]
puts "The 2D array is: #{thing}"
puts "Extension used on the thing to get at element 1 of first array:"
puts thing[0,1]

puts '-' * 20

normal = [1,2,:blah,4,5]
puts "Normal array is #{normal}"
puts "Original [] method used to get the 3rd element:"
puts normal[2]

puts '-' * 20
puts "Using the extension on the non-2D array:"
puts normal[0,1]

该程序的输出是:

The 2D array is: [[1, 2, 3], [4, 5, 6]]
Extension used on the thing to get at element 1 of first array:
2
--------------------
Normal array is [1, 2, :blah, 4, 5]
Original [] method used to get the 3rd element:
blah
--------------------
Using the extension on the non-2D array:
./test.rb:9:in `[]': Element at row 0 is not an array (ArgumentError)
    from ./test.rb:35:in `<main>'

答案 1 :(得分:1)

只需考虑消息接收器

@array[position_array]将消息[]发送给接收方@array@arrayArray的一个实例,因此调用方法Array#[]

self[position_array]将消息[]发送给接收方self。在实例方法中,self指的是该实例。由于selfThing的实例,因此调用方法Thing#[]

由于ThingObject的子类而不是Array的子类(这里没有错,所以你不应该继承Array),你的[]的实现{1}} 覆盖Array#[]。两种方法完全相互独立,就像String#[]Hash#[]

这就是我接近它的方式:

class Thing
  def initialize
    @array = [[1, 2, 3], [4, 5, 6]]
  end

  def [](i, j)
    @array[i][j]
  end
end

thing = Thing.new
thing[0, 1] #=> 2
thing[1, 1] #=> 5