Рубин, класс и наследование - PullRequest
0 голосов
/ 16 января 2019

Мне нужна помощь в понимании наследования.

class MyArray < Array
end

a = MyArray[1, 2, 3] #=> [1, 2, 3]
b = MyArray[4, 5]    #=> [4, 5]
c = a + b            #=> [1, 2, 3, 4, 5]

a.class #=> MyArray
b.class #=> MyArray
c.class #=> Array

Я не понимаю, почему результат добавления не является экземпляром класса MyArray.

Ответы [ 3 ]

0 голосов
/ 17 января 2019

Просто добавить немного к ответу Серхио с точки зрения его комментария об использовании композиции над наследованием и обмена в комментариях.

Вместо того, чтобы говорить, что MyArray - это массив, вы можете сказать, что MyArrayLike имеет и массив. Затем вы можете «перенаправить» методы, которые имеют смысл, в базовый массив, но при этом добавить собственную функциональность, которая имеет смысл для вашего класса без массива подклассов.

В Ruby даже есть несколько способов сделать это очень просто, включая модуль Forwardable .

class MyArrayLike 
   attr_reader :arr 
   def initialize( initial_arr )
      @arr = initial_arr 
   end

   def +(other)
     result = self.class.new(arr + other.arr)
     # maybe you want to do more than just concat the underlying array, if so you can do it here
     result
   end

   def first
      # for example maybe you want first to just return the first item in the underlying array.
      arr.first 
   end    
end


a = MyArrayLike.new([1,2,3])
b = MyArrayLike.new([4,5])

puts "a.class = #{a.class}"
# => a.class = MyArrayLike
puts a
# => #<MyArrayLike:0x00000000dc4b00>
a += b
puts "a.class = #{a.class}"
# => a.class = MyArrayLike
puts a 
# => #<MyArrayLike:0x00000000dc4470>

puts a.first 
# => 1
puts a.arr 
# => 1
#    2
#    3
#    4
#    5 
0 голосов
/ 17 января 2019

Добавление MyArray к MyArray для получения Array может быть нелогичным, но может быть определен метод для возврата любого класса. А в случае Array#+, который вы вызываете, просто определено, что он возвращает Array. Вот и все.

Если вы хотите, чтобы он возвращал MyArray, один из способов сделать это - определить MyArray#+ следующим образом:

class MyArray < Array
  def +other
    MyArray.new(super)
  end
end

(MyArray.new([1, 2, 3]) + MyArray.new([4, 5])).class # => MyArray

Кстати, обратите внимание, что ваше определение MyArray#initialize не имеет смысла и, следовательно, является излишним.

0 голосов
/ 16 января 2019

Я не понимаю, почему мой массив "a" не является классом "MyArray" после добавления.

Почему это должно быть (MyArray)?Определена операция конкатенации массивов, которая возвращает новый Array, вот что здесь происходит.https://ruby -doc.org / core-2.5.3 / Array.html # method-i-2B

Если вы хотите, вы можете переопределить эту операцию в своем классе, чтобы вернутьэкземпляр MyArray.Не забывайте обо всех других подобных методах.

По этой же причине плохая идея создавать подклассы стандартных коллекций.Здесь лучше использовать композицию, а не наследование.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...