Ruby,类和继承

时间:2019-01-16 20:26:43

标签: ruby inheritance

我需要了解继承的帮助。

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 :(得分:5)

  

我不明白为什么添加后我的数组“ a”不是“ MyArray”类。

为什么要(MyArray)?定义对数组的串联操作以返回新的Array,所以这就是这里发生的情况。 https://ruby-doc.org/core-2.5.3/Array.html#method-i-2B

如果需要,可以在您的类中重写该操作以返回MyArray的实例。不要忘记所有其他类似的方法。

这也是为什么子类化标准集合不是一个好主意的原因。最好在这里使用合成而不是继承。

答案 1 :(得分:3)

就Sergio关于使用合成而不是继承以及在评论中进行交换的评论而言,只需添加一点即可。

您可以说MyArrayLike 具有而不是说MyArray 。 然后,您可以“转发”对基础数组有意义的方法,但仍然添加自己的功能,该功能对于您的类没有子类化数组

是有意义的。

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 

答案 2 :(得分:3)

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定义是没有意义的,因此是多余的。