22

Ruby では、オブジェクトには、method_missing(明示的に) 定義されていないメソッドのメソッド呼び出しを処理できる便利なメソッド called があります。

obj が処理できないメッセージを送信されたときに、Ruby によって呼び出されます。symbol は呼び出されたメソッドのシンボルで、args はそれに渡された任意の引数です。デフォルトでは、このメソッドが呼び出されると、インタープリターはエラーを発生させます。ただし、メソッドをオーバーライドして、より動的な動作を提供することは可能です。以下の例では、ローマ数字で構成される名前のメソッドに応答して、対応する整数値を返すクラス Roman を作成します。

class Roman
 def romanToInt(str)
   # ...
 end
 def method_missing(methId)
   str = methId.id2name
   romanToInt(str)
 end
end

r = Roman.new
r.iv      #=> 4
r.xxiii   #=> 23
r.mm      #=> 2000

たとえば、Ruby on Rails はこれを使用して、 などのメソッドの呼び出しを許可しますfind_by_my_column_name

私の質問は、他にどの言語が に相当するものをサポートしているmethod_missingか、そしてコードに同等のものをどのように実装しているのかということです。

4

15 に答える 15

16

Smalltalk がdoesNotUnderstandRuby の親の 1 つであることを考えると、これはおそらくこのアイデアの最初の実装です。デフォルトの実装ではエラー ウィンドウが表示されますが、オーバーライドしてもっと興味深いことを行うことができます。

于 2010-05-19T13:36:40.073 に答える
12

__callPHPオブジェクトは、特別なメソッドでオーバーロードできます。

例えば:

<?php
class MethodTest {
    public function __call($name, $arguments) {
        // Note: value of $name is case sensitive.
        echo "Calling object method '$name' "
             . implode(', ', $arguments). "\n";
    }
}

$obj = new MethodTest;
$obj->runTest('in object context');
?>
于 2010-05-19T13:30:48.030 に答える
11

のいくつかのユース ケースは、たとえばmethod_missingPython で実装できます。__getattr__

class Roman(object):
  def roman_to_int(self, roman):
    # implementation here

  def __getattr__(self, name):
    return self.roman_to_int(name)

次に、次のことができます。

>>> r = Roman()
>>> r.iv
4
于 2010-05-19T13:44:00.243 に答える
10

以前にこれを探していて、SourceForge の Merd プロジェクトの一部として役立つリストを見つけました (ここではすぐに追い越されます)。


 Construct                          Language
-----------                        ----------
 AUTOLOAD                           Perl
 AUTOSCALAR, AUTOMETH, AUTOLOAD...  Perl6
 __getattr__                        Python
 method_missing                     Ruby
 doesNotUnderstand                  Smalltalk
 __noSuchMethod__(17)               CoffeeScript, JavaScript
 unknown                            Tcl
 no-applicable-method               Common Lisp
 doesNotRecognizeSelector           Objective-C
 TryInvokeMember(18)                C#
 match [name, args] { ... }         E
 the predicate fail                 Prolog
 forward                            Io

脚注付き:

  • (17) ファイアフォックス
  • (18) C# 4、「動的」オブジェクトのみ
于 2010-05-20T02:52:59.653 に答える
9

JavaScript にはnoSuchMethodがありますが、残念ながらこれは Firefox/Spidermonkey でのみサポートされています。

次に例を示します。

wittyProjectName.__noSuchMethod__ = function __noSuchMethod__ (id, args) {
   if (id == 'errorize') {
    wittyProjectName.log("wittyProjectName.errorize has been deprecated.\n" +
                         "Use wittyProjectName.log(message, " +
                         "wittyProjectName.LOGTYPE_ERROR) instead.",
                         this.LOGTYPE_LOG);
    // just act as a wrapper for the newer log method
    args.push(this.LOGTYPE_ERROR);
    this.log.apply(this, args);
  }
}
于 2010-05-20T02:36:53.680 に答える
9

Perl にはAUTOLOAD、サブルーチンとクラス/オブジェクト メソッドで動作するものがあります。

サブルーチンの例:

use 5.012;
use warnings;

sub AUTOLOAD {
    my $sub_missing = our $AUTOLOAD;
    $sub_missing =~ s/.*:://;
    uc $sub_missing;
}

say foo();   # => FOO

クラス/オブジェクト メソッド呼び出しの例:

use 5.012;
use warnings;

{
    package Shout;

    sub new { bless {}, shift }

    sub AUTOLOAD {
        my $method_missing = our $AUTOLOAD;
        $method_missing =~ s/.*:://;
        uc $method_missing;
    }
}

say Shout->bar;         # => BAR

my $shout = Shout->new;
say $shout->baz;        # => BAZ
于 2010-05-19T14:13:12.760 に答える
8

Objective-C は同じことをサポートし、それをforwardingと呼びます。

于 2010-05-19T13:27:55.287 に答える
8

これは、メタテーブルのキーを設定することによって Lua で実現さ__indexます。

t = {}
meta = {__index = function(_, idx) return function() print(idx) end end}
setmetatable(t, meta)

t.foo()
t.bar()

このコードは次を出力します。

foo
bar
于 2010-05-20T03:15:04.240 に答える
5

Common Lisp では、 Common Lisp Hyper Specno-applicable-methodに従って、この目的に使用できます。

ジェネリック関数 no-applicable-method は、ジェネリック関数が呼び出され、そのジェネリック関数のメソッドが適用できない場合に呼び出されます。デフォルトのメソッドはエラーを通知します。

汎用関数 no-applicable-method は、プログラマーが呼び出すことを意図していません。プログラマーは、そのためのメソッドを作成できます。

たとえば、次のようになります。

(defmethod no-applicable-method (gf &rest args)
  ;(error "No applicable method for args:~% ~s~% to ~s" args gf)
  (%error (make-condition 'no-applicable-method :generic-function gf :arguments args) '()
        ;; Go past the anonymous frame to the frame for the caller of the generic function
        (parent-frame (%get-frame-ptr))))
于 2010-05-19T14:08:02.893 に答える
5

C#には、動的オブジェクト ( DynamicObjectから継承)用にTryInvokeMemberが追加されました。

于 2010-05-20T02:55:31.083 に答える
3

Actionscript 3.0には、Proxyこの機能を提供するために拡張できるクラスがあります。

dynamic class MyProxy extends Proxy {
  flash_proxy override function callProperty(name:*, ...rest):* {
    try {
      // custom code here
    }
    catch (e:Error) {
      // respond to error here
    }
}  
于 2010-05-19T13:32:46.890 に答える
2

CFML(ColdFusion、Railo、OpenBD)では、onMissingMethod()コンポーネント内で定義されたイベントハンドラーは、そのコンポーネントで未定義のメソッド呼び出しを受け取ります。引数missingMethodNamemissingMethodArgumentsは自動的に渡されるため、欠落しているメソッド呼び出しを動的に処理できます。これは、さまざまなCFMLエンジンに組み込まれる前に、暗黙的なセッター/ゲッタースキームの作成を容易にするメカニズムです。

于 2010-05-20T01:55:38.967 に答える
2

これに相当するのIoは、メソッドを使用するforwardことです。

ドキュメントから:

オブジェクトがメッセージに応答しない場合、「転送」メソッドがあればそれを呼び出します。

以下に簡単な例を示します。

Shout := Object clone do (
    forward := method (
        method_missing := call message name
        method_missing asUppercase
    )
)

Shout baz println     # => BAZ

/I3az/

于 2011-05-12T19:07:10.140 に答える
2

Tcl にも似たようなものがあります。見つからないコマンドを呼び出すと、不明なプロシージャが呼び出されます。普段使うものではありませんが、あると便利です。

于 2010-05-19T14:12:31.150 に答える
1

Boo has - how-can-i-intercept-a-meth-call-in-booIQuackFuに SO に関する優れた要約が既にあります

次に例を示します。

class XmlObject(IQuackFu):
_element as XmlElement 

def constructor(element as XmlElement):
    _element = element 

def QuackInvoke(name as string, args as (object)) as object:
    pass # ignored 

def QuackSet(name as string, parameters as (object), value) as object:
    pass # ignored 

def QuackGet(name as string, parameters as (object)) as object:
    elements = _element.SelectNodes(name)
    if elements is not null:
        return XmlObject(elements[0]) if elements.Count == 1
        return XmlObject(e) for e as XmlElement in elements 

override def ToString():
    return _element.InnerText 
于 2010-05-20T02:49:22.110 に答える