Jus*_*ier 21 language-features programming-languages method-missing
在Ruby中,对象有一个方便的方法method_missing,允许人们处理甚至没有(显式)定义的方法的方法调用:
当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
Run Code Online (Sandbox Code Playgroud)
例如,Ruby on Rails使用它来允许调用诸如的方法find_by_my_column_name.
我的问题是,其他语言支持的等价物method_missing,以及如何在代码中实现等效语言?
Joh*_*ley 15
Smalltalk有doesNotUnderstand消息,这可能是这个想法的原始实现,因为Smalltalk是Ruby的父母之一.默认实现显示一个错误窗口,但可以覆盖它以执行更有趣的操作.
tyl*_*mac 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');
?>
Run Code Online (Sandbox Code Playgroud)
mik*_*kej 11
一些用例method_missing可以使用__getattr__例如Python在Python中实现
class Roman(object):
def roman_to_int(self, roman):
# implementation here
def __getattr__(self, name):
return self.roman_to_int(name)
Run Code Online (Sandbox Code Playgroud)
然后你可以这样做:
>>> r = Roman()
>>> r.iv
4
Run Code Online (Sandbox Code Playgroud)
Perl AUTOLOAD适用于子例程和类/对象方法.
子程序示例:
use 5.012;
use warnings;
sub AUTOLOAD {
my $sub_missing = our $AUTOLOAD;
$sub_missing =~ s/.*:://;
uc $sub_missing;
}
say foo(); # => FOO
Run Code Online (Sandbox Code Playgroud)
类/对象方法调用示例:
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
Run Code Online (Sandbox Code Playgroud)
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);
}
}
Run Code Online (Sandbox Code Playgroud)
这是通过设置元表的__index键在Lua中完成的.
t = {}
meta = {__index = function(_, idx) return function() print(idx) end end}
setmetatable(t, meta)
t.foo()
t.bar()
Run Code Online (Sandbox Code Playgroud)
此代码将输出:
foo
bar
Run Code Online (Sandbox Code Playgroud)
之前我一直在寻找这个,并在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
Run Code Online (Sandbox Code Playgroud)
用脚注:
在Common Lisp中,no-applicable-method可以用于此目的,根据Common Lisp Hyper Spec:
当调用泛型函数并且该泛型函数上没有方法适用时,将调用泛型函数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))))
Run Code Online (Sandbox Code Playgroud)
C#现在有TryInvokeMember,用于动态对象(继承自DynamicObject)