【问题标题】:Arity of method delegated with method_missing用 method_missing 委托的方法的数量
【发布时间】:2012-11-27 05:03:58
【问题描述】:

当我将 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

A 实例上的方法的arity 返回-1,而与$delegation_target 上的方法的arity 无关:

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 来自哪里?而且,有没有办法让它对于任何可能的方法名称mA.new.method(m).arity 返回$delegation_target.method(m) 的arity(如果已定义)?

【问题讨论】:

    标签: ruby delegation method-missing arity


    【解决方案1】:

    Object#method 以特殊方式处理 respond_to_missing?method_missing。让我们深入研究 Ruby C 源代码,看看会发生什么:

    Object#method 开始,我们调用mnew,它为调用它的对象和传递的id 创建一个新的Method 对象。在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 的数量与我们得到的相同来确认我们的怀疑:

    A.new.method(:method_missing).arity  #=> -1
    

    顺便说一句,-1 的数量意味着该方法可以接受无限数量的参数。

    至于你是否可以让它返回被调用方法的“真实”数量……不,你不能。一方面,Ruby 不对您的 method_missing 中发生的事情做出任何假设,甚至不知道它只是委托给其他方法。

    【讨论】:

      【解决方案2】:

      一个负数意味着有一个最终的 * 前缀参数。如果有一个必需参数后跟一个带 * 前缀的参数(所以一个必需参数和一个可选的附加量),那么元数将表示为 -2,因此 -n-1,其中 n 是必需参数的数量。

      -n-1 被称为 n 的反码,ruby 甚至有一个运算符来获取所需参数的数量,~ 运算符。

      p ~A.new.method(:foo).arity #=> 0
      

      【讨论】:

        猜你喜欢
        • 2016-11-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多