当我将类A
的实例上的方法委托给$delegation_target
时,如下所示:
$delegation_target = ""
class A
def method_missing *args, ≺ $delegation_target.send(*args, &pr) end
def respond_to_missing? *args; $delegation_target.respond_to?(*args) end
end
arity
实例的方法的A
会返回-1
,而不管arity
上$delegation_target
方法的def $delegation_target.foo; end
A.new.method(:foo).arity # => -1
def $delegation_target.foo arg1; end
A.new.method(:foo).arity # => -1
def $delegation_target.foo arg1, arg2; end
A.new.method(:foo).arity # => -1
def $delegation_target.foo arg1, arg2, arg3; end
A.new.method(:foo).arity # => -1
:
-1
m
来自何处?并且,有没有办法让它,以便,对于任何可能的方法名称A.new.method(m).arity
,$delegation_target.method(m)
返回{{1}}的arity(如果已定义)?
答案 0 :(得分:6)
Object#method
处理respond_to_missing?
& method_missing
以特殊的方式。让我们深入研究Ruby C源代码,看看会发生什么:
从Object#method
开始,我们调用mnew
,它会为调用它的对象创建一个新的Method
对象并传递id。在mnew
的来源中,我们可以很容易地看到未定义方法时的特殊处理,但respond_to_missing?
在给定id时返回true
:
if (UNDEFINED_METHOD_ENTRY_P(me)) {
ID rmiss = rb_intern("respond_to_missing?");
VALUE sym = ID2SYM(id);
if (obj != Qundef && !rb_method_basic_definition_p(klass, rmiss)) {
if (RTEST(rb_funcall(obj, rmiss, 2, sym, scope ? Qfalse : Qtrue))) {
def = ALLOC(rb_method_definition_t);
def->type = VM_METHOD_TYPE_MISSING;
def->original_id = id;
// ...
def->type = VM_METHOD_TYPE_MISSING;
很重要。找到definition for VM_METHOD_TYPE_MISSING
,我们发现它是“method_missing(id)
”的“包装器”。所以返回的方法实际上只是method_missing
,第一个参数已经被指定为你最初想要得到的方法的id。
我们可以通过验证method_missing
的arity与我们获得的相同来证实我们的怀疑:
A.new.method(:method_missing).arity #=> -1
顺便说一下,-1
的arity意味着该方法可以采用无限数量的参数。
至于你是否可以让它返回被调用方法的“真实”...不,你不能。首先,Ruby不会对你method_missing
中发生的事情做出任何假设,甚至不知道它只是委托给其他方法。
答案 1 :(得分:3)
负面arity意味着有一个最终的* -prefixed参数。如果有一个必需参数后跟一个* -prefixed参数(所以一个必需参数和一个可选的附加金额),那么arity将表示为-2,所以-n-1,其中n是所需参数的数量。
-n-1被称为n的一个补码,而ruby甚至有一个运算符来获取所需参数的数量,即~
运算符。
p ~A.new.method(:foo).arity #=> 0