Rubyの関数呼び出しとsuper


最近Rubyの基本的な文法の知識を固めて、ここで以前いくつか知らなかった特性を一つ一つまとめます.
Rubyではmethodの繰り返し宣言が許可されており、適切な場合には呼び出し(superキーワードを使用)も許可されています.
ここではいくつかの例を通して、Rubyのmethod検索パスと方法、superの使用とパラメータの問題を共有します.
まず、このような例を見てみましょう.
class A
  def a
    p 'a 1'
  end
  def a
    p 'a 2'
    super
    p 'a 2 END'
  end
end

b = A.new
b.a

出力結果は次のとおりです.
Outputは
:!ruby method01.rb
"a 2"
method01.rb:7:in `a': super: no superclass method `a' (NoMethodError) from method01.rb:13
shell returned 1
結果から,同じメソッド(同じmethod名とパラメータ数)を1つのclassで繰り返し宣言すると,元のメソッドは後のメソッドによって完全に上書きされる(すなわち,元の定義が無効になる)ことが分かった.もちろんこれは普通の状況で、Javaでは文法は直接許されません.ここは許可されていますが、実際には意味がありません.では、ここのsuperは何の意味があるのでしょうか.ゆっくり見てみましょう.
2つ目の例を見てみましょう
class B
  def a 
    p 'B a 1'
  end
end

class A < B
  def a
    p 'a 1'
  end
  def a
    p 'a 2'
    super
    p 'a 2 END'
  end
end

b = A.new
b.a

出力結果:
Outputは
:!ruby method01.rb
"a 2"
"B a 1"
"a 2 END"
奇妙なようですね.これがRubyのsuperキーワードの一部の役割です.実はJavaのMethod overwriteに似ていてsuperを通っています.XXXXXXmethodは祖先メソッドを呼び出し、実行の順序も同様です.例では,Aに定義されていたaメソッドが確かに役に立たないことも見た.
クラス階層関係の記述
A 
Moduleにも似たような効果があります.
module B
  def a 
    p 'B a 1'
  end
end

class A
  include B
  def a
    p 'a 1'
  end
  def a
    p 'a 2'
    super
    p 'a 2 END'
  end
end

b = A.new
b.a

出力結果は上のClass-Classの例と同じです.
Outputは
:!ruby method01.rb
"a 2"
"B a 1"
"a 2 END"
 
クラス階層関係の記述
A上の2つの階層関係もmethodの検索順序です.ModuleとClassは同等の効力を持っているようですが、2つを組み合わせてみましょう.
class B
  def a
    p 'B a 1'
  end
end

module M 
  def a 
    p 'M a 1'
    super
    p 'M a END'
  end
end

class A < B
  include M
  def a
    p 'a 1'
  end
  def a
    p 'a 2'
    super
    p 'a 2 END'
  end
end

b = A.new
b.a

出力結果:
Outputは
:!ruby method01.rb
"a 2"
"M a 1"
"B a 1"
"M a END"
"a 2 END"
この階層を見ることができます
クラス階層の書き込み
Aつまり、Moduleと祖先Classが同時に現れた場合、プログラムはまずModuleで探します.では、先祖ClassにもこのModuleが含まれていたらどうなるのでしょうか.
module M 
  def a 
    p 'M a 1'
  end
end

class B
  def a
    p 'B a 1'
    super
    p 'B a END'
  end
  include M
end

class A < B
  include M
  def a
    p 'a 1'
  end
  def a
    p 'a 2'
    super
    p 'a 2 END'
  end
end

b = A.new
b.a

出力結果:
Outputは
:!ruby method01.rb
"a 2"
"B a 1"
"M a 1"
"B a END"
"a 2 END"
Moduleを祖先に混入すると、この階層はまた変更されます.
クラス階層の書き込み
Aつまり、もし「老子」も「小僧」も「XXX」を持ちたいなら、この「XXX」は「老子」のものになるに違いない.
次に,この呼び出しsuperがパラメータも伝達したかどうかについて議論する.
『Ruby For Rails』には、次のような記述があります.
superのパラメータ伝達書
裸語superで祖先/モジュールメソッド(callee)を呼び出すと、呼び出し者(caller)のすべてのメソッドパラメータが渡されます.
super()で呼び出すと、callerのパラメータは渡されません.
super(a,b)で呼び出すと、パラメータa,bの一部が伝達される.
効果を1つの例で見てみましょう.
module M 
  def a(x=5,y=6) 
    p 'M a 1'
    p x
    p y
  end
end

class B
  def a(x=3,y=4)
    p 'B a 1'
    p x
    p y
    super(x)
    p 'B a END'
  end
  include M
end

class A < B
  include M
  def a
    p 'a 1'
  end
  def a(x=1,y=2)
    p 'a 2'
    p x
    p y
    super
    p 'a 2 END'
    super()
  end
end

b = A.new
b.a(-1,-2)

出力結果:
Outputは
:!ruby method01.rb
"a 2"
-1 -2
"B a 1"
-1 -2
"M a 1"
-1
6
"B a END"
"a 2 END"
"B a 1"
3 4
"M a 1"
3
6
"B a END"
やはり、確かに違う効果があります.ただし、super()とsuper(a)を使用する場合は、パラメータデータが不完全であるため、元のメソッドではデフォルトのパラメータ値が必要であることに注意してください.
最後に、総合的な例を示しましょう.
 
中には多くの間違いと冗長性があります.まず自分で出力結果を見てから実際の結果を見てほしいです.もっと多くの収穫があります.
module M
  def report( a = 4, b =5)
    p "M report begin: a=#{a},b=#{b}"
    a = 6
    super(a)
    p "M report end"
  end
end

class B
  def report(a=11,b=12)
    p "B report 1 begin: a=#{a},b=#{b}"
    p "B report 1 end"
  end
  def report(a=13,b=14)
    p "B report 2 begin: a=#{a},b=#{b}"
    #super
    p "B report 2 end"
  end
end

class C < B
  def report( a=8,b=9)
    p "C report 1 begin: a=#{a},b=#{b}"
    p "C report 1 end"
  end
  def report( a=7,b=3)
    p "C report 2 begin: a =#{a},b=#{b}"
    super()
    p "C report 2 End"
  end
  include M
end

class D < C
  def report( a = 2, b=1)
    p "D report 1 begin: a=#{a},b=#{b}"
    super(a,b)
    p "D report 1 end"
  end
  include M
  def report(a = -2, b=-1)
    p "D report 2 begin: a=#{a},b=#{b}"
    super
    p "D report 2 end"
  end
end

d = D.new
d.report

出力結果:
Outputは
"
D report
2 begin:
a=-2,b=-1 "
"
C report
2 begin:
a =-2,b=-1 "
"
M report begin:
a=4,b=5 "
"
B report
2 begin:
a=6,b=14 "
"B report
2 end"
"M report end"
"C report
2 End"
"D report
2 end"
例を通して、method検索呼び出し法則と具体的なsuperが使用されていることをより明確に理解できるはずです.
以下にまとめます.
  • 同じclassとmoduleでは、1つのmethodが1つしか有効ではないことを繰り返し宣言します(superでも「古い」いくつかを呼び出すことはできません).
  • 一般的な手順は、このインスタンスオブジェクトのメソッド-->このオブジェクトに対応するクラスのメソッド-->このオブジェクトに含まれるmodule(includeが祖先に存在しないことを保証する)-->祖先-(再帰的)->......
  • super伝達パラメータは3種類(裸語、空、部分)
  • である.
  • このような難しい方法の構造を書かないでください