nesheep5's blog

子持ちWebエンジニアのブログ。プログラミング・仕事効率化・健康・子育て etc...

【Ruby入門】superの振る舞いについて

最近Rubyを勉強しています。
Effective Rubyでsuperの振る舞いについて勉強していたところ、サンプルソースが少しわかりにくかったので自分なりに噛み砕いてみました。

1.カッコの有無による振る舞いの違い

  • オーバーライドするメソッドに引数を渡したくない場合は、 super()とする 。
    superではないことに注意。

サンプルソース

class SuperClass
  def m1(x=0, y=0)
    puts "x=#{x}, y=#{y}"
  end
end

class SubClass < SuperClass
  def m1(x, y)
    super(1, 2) # => x=1, y=2
    super(x, y) # => x=a, y=b
    super x, y  # => x=a, y=b
    super       # => x=a, y=b
    super()     # => x=0, y=0 (引数なしで呼び出し)
  end
end

subclass = SubClass.new
subclass.m1('a', 'b')

2.superに対応するメソッドの探索順序

  • スーパークラスのメソッド、moduleのメソッドを呼び出す
  • <クラス>.ancestorsメソッドで返却される、親クラスの配列順にメソッド探索を行う

サンプルソース

class SuperClass
  def m
    puts "SuperClass"
  end
end

module ModuleA
  def m
    puts "ModuleA"
  end
end

module ModuleB
  def m
    puts "ModuleB"
  end
end

# 検証
class SubClass < SuperClass
  def m
    super #=> SuperClass
  end
end

class IncludeModule
  include ModuleA

  def m
    super #=> ModuleA
  end
end

class IncAndSub < SuperClass
  include ModuleA
  include ModuleB
  def m
    p IncAndSub.ancestors #=> [IncAndSub, ModuleB, ModuleA, SuperClass, Object, PP::ObjectMixin, Kernel, BasicObject]
    super #=> ModuleB (ancestorsの結果の順に遡ってメソッドを探す)
  end
end

SubClass.new.m
IncludeModule.new.m
IncAndSub.new.m

3.コンストラクタでのsuperの振る舞い

  • Javaと違い、コンストラクタ(initializeメソッド)は暗黙的に親クラスのコンストラクタを呼ぶわけではない
  • 親クラスのコンストラクタを呼びたい場合は、initializeメソッド明示的にsuperを記述する必要がある

サンプルソース

class Parent
  attr_accessor :name
  def initialize
    @name = 'Howord'
  end
end

class Child1 < Parent
  attr_accessor :grade
  def initialize
    # superを指定しない
    @grade = 8
  end
end

class Child2 < Parent
  attr_accessor :grade
  def initialize
    super
    @grade = 8
  end
end

c1 = Child1.new #=> #<Child:0x00007fd583b2e6b0 @grade=8>
c1.name #=> nil (暗黙的に親クラスのinitializeが呼ばれるわけではない)

c2 = Child2.new #=> #<Child:0x00007fd583b2e6b0 @grade=8>
c2.name #=> Howord

参考

書籍:Effective Ruby

  • 項目7:superのふるまいがひと通りではないことに注意しよう
  • 項目8:サブクラスを初期化するときにはsuperを呼び出そう
Effective Ruby
Effective Ruby
posted with amazlet at 18.02.14
Peter J. Jones
翔泳社
売り上げランキング: 263,592