2

次の2つのクラスがあります。

(defclass person () ())

(defmethod speak ((s person) string)
    (format t "-A" string))

(defmethod speak :before ((s person) string)
    (print "Hello! "))

(defmethod speak :after ((s person) string)
    (print "Have a nice day!"))


(defclass speaker (person) ())

(defmethod speak ((i speaker) string)
  (print "Bonjour!"))


(speak (make-instance 'speaker) "Can I help yoU?")

そして、これの出力は次のとおりです。

"Hello! "                                                                                                                                                                                                                                               
"Bonjour!"                                                                                                                                                                                                                                              
"Have a nice day!" 

私が理解しようとしているのは、これらのメソッドが「順序」に関してどのように実行されるかです。何が起こっているのか、その理由を理解できないようです。おそらくこれにはルールの優先順位がありますが、どこにあるのかわかりません。たとえば、"Hello!Can I help you"この場合、なぜ発砲しないのでしょうか?

4

3 に答える 3

9

メソッドの周りに何もない場合、メソッド適用の順序は次のとおりです。最も具体的なメソッドから最も具体的でないメソッドへのすべての前のメソッド、次に最も具体的なプライマリメソッド、そして最も具体的ではないメソッドから最も具体的なメソッドの後です。あなたの場合、2 つの主要な方法 (名前の横に :before または :after がない方法) があります。1 つは人物を指定し、もう 1 つはスピーカーを指定します。Speaker は person よりも具体的であるため、speaker primary メソッドのみが呼び出されます。複数のプライマリ メソッドを呼び出したい場合は、call-next-method を参照してください。

于 2015-06-05T03:14:47.330 に答える
3

すでに受け入れられている回答があるように見えますが、Common Lisp には HyperSpec に非常に優れたドキュメントがいくつかあり、何が起こるかについての完全な説明がどこにあるかを知っておくと便利です。この場合、それは7.6.6.2 Standard Method Combinationであり、次のように述べています (省略):

標準的なメソッドの組み合わせのセマンティクスは次のとおりです。

  • 回避方法がある場合は、最も具体的な方法が呼び出されます。ジェネリック関数の値を提供します。

  • around メソッドの本体内で、call-next-method を使用して next メソッドを呼び出すことができます。次のメソッドが戻ると、おそらく返された値に基づいて、around メソッドがさらにコードを実行できます。call-next-method が使用され、呼び出す適切なメソッドがない場合、ジェネリック関数 no-next-method が呼び出されます。関数 next-method-p を使用して、次のメソッドが存在するかどうかを判断できます。

  • around メソッドが call-next-method を呼び出す場合、次に最も具体的な around メソッドが呼び出されます (該当する場合)。around メソッドがない場合、または call-next-method が最も特異性の低い around メソッドによって呼び出された場合、他のメソッドは次のように呼び出されます。

    • before メソッドはすべて、最も具体的な順に呼び出されます。それらの値は無視されます。call-next-method が before メソッドで使用されている場合、エラーが通知されます。

    • 最も具体的なプライマリ メソッドが呼び出されます。プライマリ メソッドの本体内で、call-next-method を使用して、次に具体的なプライマリ メソッドを呼び出すことができます。そのメソッドが戻ると、おそらく返された値に基づいて、前のプライマリ メソッドがさらにコードを実行できます。call-next-method が使用され、適用可能なプライマリ メソッドがこれ以上ない場合、ジェネリック関数 no-next-method が呼び出されます。関数 next-method-p を使用して、次のメソッドが存在するかどうかを判断できます。call-next-method を使用しない場合、最も具体的なプライマリ メソッドのみが呼び出されます。

    • after メソッドはすべて、最も具体的で最後の順序で呼び出されます。それらの値は無視されます。after メソッドで call-next-method を使用すると、エラーが通知されます。

  • アラウンド メソッドが呼び出されなかった場合、最も具体的なプライマリ メソッドが、ジェネリック関数によって返される値を提供します。最も具体的でない around メソッドで call-next-method の呼び出しによって返される値は、最も具体的なプライマリ メソッドによって返される値です。

そのページの最後に、動作とその動機を説明する特に役立つ図があります。

before メソッドは最も具体的な順序で実行され、after メソッドは最も具体的でない順序で実行されます。この違いの設計上の根拠は、例を使用して説明できます。クラス C1 が、before メソッドと after メソッドを追加することによって、そのスーパークラス C2 の動作を変更するとします。クラス C2 の動作が C2 のメソッドによって直接定義されているか、そのスーパークラスから継承されているかは、クラス C1 のインスタンスのメソッド呼び出しの相対的な順序には影響しません。クラス C1 の before メソッドは、クラス C2 のすべてのメソッドの前に実行されます。クラス C1 の after メソッドは、クラス C2 のすべてのメソッドの後に実行されます。

対照的に、オールラウンド メソッドは、他のメソッドが実行される前に実行されます。したがって、特定性の低い around メソッドは、より特定性の高いプライマリ メソッドの前に実行されます。

基本メソッドのみが使用され、call-next-method が使用されない場合、最も具体的なメソッドのみが呼び出されます。つまり、より具体的なメソッドは、より一般的なメソッドを隠します。

于 2015-06-05T11:38:18.873 に答える