2010-05-19 158 views
21

在Ruby中,對象具有定義了稱爲method_missing一個方便的方法,它允許一個處理對於尚未甚至已(明確)的方法的方法調用:與其他語言中的Ruby的method_missing是否等價?

由紅寶石調用時物鏡被髮送的消息時,它不能處理的。符號是調用方法的符號,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等效,以及如何在代碼中實現等效功能?

回答

11

method_missing的一些使用案例可以使用__getattr__例如__getattr__在Python中實現。

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 
+0

'roman_to_int'有空的實現,爲什麼r.iv返回4? – Tim 2017-07-08 01:09:19

+0

@Tim你應該填寫空白代碼,返回一個值。他只是決定不顯示所有細節。這可以用羅馬數字轉換器來實現。 – 2017-07-08 01:21:36

8

Objective-C支持同樣的事情,並將其稱爲forwarding

12

PHP對象可以用__call特殊方法重載。

例如:

<?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'); 
?> 
2

的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 
    } 
} 
15

Smalltalk中有doesNotUnderstand消息,這可能是原始的實現這個想法,因爲Smalltalk是Ruby的父母之一。默認實現顯示一個錯誤窗口,但可以覆蓋它來做更有趣的事情。

+0

酷!但是有沒有一個例子可以讓你知道如何使用這條消息? – 2010-05-19 14:02:28

+1

「與#become:相結合,這會導致兩個對象在內存中交換位置,#doesNotUnderstand:的這種功能對於實現ProxyObjects非常有用,例如對象關係映射框架中所需的」http://c2.com/cgi/ wiki?DoesNotUnderstand – 2010-05-19 19:45:58

5

Common Lisp中,no-applicable-method可以用於此目的,根據Common Lisp Hyper Spec

通用功能不適用的法在調用泛型函數時調用,並且該泛型函數上的任何方法都不適用。默認方法發出錯誤信號。

通用函數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)))) 
+2

儘管如此,我不認爲這會給你從Ruby中獲得的同樣的語法糖。在'r.xxiii'的例子中,爲了從(XXIII R)調用NO-APPLICABLE-METHOD,你需要先定義一個名爲XXIII的泛型函數,對嗎? – 2011-07-14 04:13:54

2

的Tcl有類似的東西。任何時候你打電話找不到任何命令,程序unknown將被調用。雖然它不是你通常使用的東西,但它有時候可能非常方便。

8

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 
2

在CFML(ColdFusion的,Railo,OpenBD),則onMissingMethod()事件處理程序,組件內所定義,將接收對該組件未定義的方法調用。自動傳入參數missingMethodNamemissingMethodArguments,允許動態處理缺少的方法調用。這是在隱式setter/getter方案開始構建到各種CFML引擎之前促進創建的機制。

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); 
    } 
} 
1

Boo對於IQuackFu - 已經有在how-can-i-intercept-a-method-call-in-boo

這裏的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 
7

我一直在尋找這之前,發現一個useful list(很快被超越)作爲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,只爲 「動態」 對象
5

C#現在有TryInvokeMember,對於動態對象(繼承自DynamicObject

+4

DynamicObject在這方面甚至還有一些更多的方法,儘管TryInvokeMember與method_missing直接等價。還有ExpandoObject,它允許在運行時添加屬性。根據你實際想要解決的問題,這些也許是好方法。 – OregonGhost 2010-05-20 10:39:55

8

這是通過設置metatable__index密鑰在Lua中完成的。

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

t.foo() 
t.bar() 

此代碼將輸出:

foo 
bar 
2

及其等效中Io使用forward方法。

從文檔:

如果對象不回覆短信,它會調用它的「前進」的方法,如果它有一個....

下面是一個簡單的例子:

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

Shout baz println  # => BAZ 

/I3az/

相關問題