最近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
参考
- 項目7:superのふるまいがひと通りではないことに注意しよう
- 項目8:サブクラスを初期化するときにはsuperを呼び出そう
Effective Ruby
posted with amazlet at 18.02.14