15

如何Proc#==评价?RDoc说:

prc == other_proc → 真或假

如果 prc 与 other_proc 是同一个对象,或者它们都是具有相同主体的 proc,则返回 true。

但不清楚什么算作“同一个身体”。一个条件似乎是 arity 必须相同:

->{} == ->{} # => true
->{} == ->x{} # => false
->x{} == ->x{} # => true
->x{} == ->y{} # => true
->x{} == ->y,z{} # => false

但不止于此。正如 RDoc 所说,身体很重要:

->{nil} == ->{nil} # => true
->{nil} == ->{false} # => false
->{false} == ->{false} # => true

但与此同时,proc 似乎没有被完全评估:

->{} == ->{nil} # => false
->{false} == ->{1 == 2} # => false

身体被评估到什么程度?

4

2 回答 2

9

在 Ruby 2.0 中发生了变化,所以你不应该尝试比较Procs。==除非它们是完全相同的对象,否则它们不会。

可以在这里找到讨论。

如果您确实需要比较两个块的代码并且正在使用MRI,您可以使用RubyVM::InstructionSequence.disassemble(block)Ruby 2.0,甚至更好RubyVM::InstructionSequence.of(block)

于 2013-01-23T19:53:43.027 回答
4

要回答这个问题,让我们看看 proc 比较代码

static VALUE
proc_eq(VALUE self, VALUE other)
{
    if (self == other) {
        return Qtrue;
    }
    else {
        if (rb_obj_is_proc(other)) {
           rb_proc_t *p1, *p2;
           GetProcPtr(self, p1);
           GetProcPtr(other, p2);
           if (p1->envval == p2->envval &&
              p1->block.iseq->iseq_size == p2->block.iseq->iseq_size &&
              p1->block.iseq->local_size == p2->block.iseq->local_size &&
              MEMCMP(p1->block.iseq->iseq, p2->block.iseq->iseq, VALUE,
                    p1->block.iseq->iseq_size) == 0) {
                 return Qtrue;
           }
       }
    }
    return Qfalse;
}

第一个 if 分支非常简单 - 比较它的两个 proc 是同一个对象。第二个有点棘手。它检查两个 proc 是否具有相同的 envval、iseq(proc 实现)的大小、局部变量的大小,并比较两个实现是否相同。这意味着在语法级别而不是在 proc 结果上检查 proc 相等性。

让我们以https://gist.github.com/4611935 第一个示例工作得很好,因为局部变量的数量相同并且操作顺序相同。将 123 分配给局部变量。第二个样本被视为不相同,因为操作顺序不同 - 您将 123 分配给不同的变量。

但是,是的,proc 比较非常令人困惑,并且我认为已从 ruby​​ 2.0 中删除。现在 procs 通过其 id 与常规对象进行比较。

于 2013-01-23T19:58:02.733 回答