Rubyの関数呼び出しとsuper
最近Rubyの基本的な文法の知識を固めて、ここで以前いくつか知らなかった特性を一つ一つまとめます.
Rubyではmethodの繰り返し宣言が許可されており、適切な場合には呼び出し(superキーワードを使用)も許可されています.
ここではいくつかの例を通して、Rubyのmethod検索パスと方法、superの使用とパラメータの問題を共有します.
まず、このような例を見てみましょう.
出力結果は次のとおりです.
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つ目の例を見てみましょう
出力結果:
Outputは
:!ruby method01.rb
"a 2"
"B a 1"
"a 2 END"
奇妙なようですね.これがRubyのsuperキーワードの一部の役割です.実はJavaのMethod overwriteに似ていてsuperを通っています.XXXXXXmethodは祖先メソッドを呼び出し、実行の順序も同様です.例では,Aに定義されていたaメソッドが確かに役に立たないことも見た.
クラス階層関係の記述
A
Moduleにも似たような効果があります.
出力結果は上のClass-Classの例と同じです.
Outputは
:!ruby method01.rb
"a 2"
"B a 1"
"a 2 END"
クラス階層関係の記述
A上の2つの階層関係もmethodの検索順序です.ModuleとClassは同等の効力を持っているようですが、2つを組み合わせてみましょう.
出力結果:
Outputは
:!ruby method01.rb
"a 2"
"M a 1"
"B a 1"
"M a END"
"a 2 END"
この階層を見ることができます
クラス階層の書き込み
Aつまり、Moduleと祖先Classが同時に現れた場合、プログラムはまずModuleで探します.では、先祖ClassにもこのModuleが含まれていたらどうなるのでしょうか.
出力結果:
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つの例で見てみましょう.
出力結果:
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)を使用する場合は、パラメータデータが不完全であるため、元のメソッドではデフォルトのパラメータ値が必要であることに注意してください.
最後に、総合的な例を示しましょう.
中には多くの間違いと冗長性があります.まず自分で出力結果を見てから実際の結果を見てほしいです.もっと多くの収穫があります.
出力結果:
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種類(裸語、空、部分) である.このような難しい方法の構造を書かないでください
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
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 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が使用されていることをより明確に理解できるはずです.
以下にまとめます.