2013-01-23 29 views
15

Proc#== được đánh giá như thế nào? RDoc nói:`ProC# == 'được đánh giá như thế nào?

prc == other_proc → true hoặc false

trả về true nếu prc là cùng một đối tượng như other_proc, hoặc nếu họ đều procs với cùng một cơ thể.

Nhưng không rõ điều gì được tính là có "cùng một nội dung". Một điều kiện có vẻ là sự tinh thần phải giống nhau:

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

Nhưng còn nhiều hơn thế. Như rdoc nói, cơ thể quan trọng:

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

Nhưng cùng một lúc, có vẻ như các proc không được đánh giá đầy đủ:

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

ở mức độ nào là cơ quan thẩm định?

+1

Tôi tưởng tượng mã trong cơ thể phải giống nhau, không phải kết quả của việc đánh giá. –

+1

Tôi đã nghĩ cây phân tích cú pháp phải giống hệt nhau, nhưng ... '-> {nil} == -> {nil; nil} # => true' Hoặc có lẽ nil đầu tiên bị tước hình thành cây nguồn vì nó không có tác dụng hay ý nghĩa gì? –

+1

Ngoài ra: 'a, b = -> {}, -> {}; a == b # => true', nhưng 'a = -> {} [newline] b = -> {}; a == b # => sai'. Lưu ý dòng mới PHẢI là một dòng mới; nếu bạn sử dụng dấu chấm phẩy, 'a' bằng' b'. WTF thực sự. –

Trả lời

9

Điều này có changed in Ruby 2.0, vì vậy bạn không nên thử so sánh Proc s. Chúng sẽ không là == trừ khi chúng chính xác là cùng một đối tượng.

Cuộc thảo luận có thể là found here.

Nếu bạn thực sự cần so sánh mã của hai khối và đang sử dụng MRI, bạn có thể phát xung quanh với RubyVM::InstructionSequence.disassemble(block) hoặc thậm chí tốt hơn trong Ruby 2.0 RubyVM::InstructionSequence.of(block).

+1

So sánh việc tháo gỡ các khối là một kỹ thuật thú vị.Nó có những hạn chế, rõ ràng - các procs phải chia sẻ một số dòng (bạn có thể giả mạo điều này với eval nếu cần thiết), và các giá trị của các biến trong ràng buộc của proc không được tính đến. Nhưng tôi đã có thể tạo một bộ nhớ cache phương pháp có tính đến đối số khối. Mẹo hay. – rcrogers

+1

Ngoài ra, ProC# to_source được cho là sẽ được triển khai đôi khi: http://bugs.ruby-lang.org/issues/2080 – rcrogers

4

Để trả lời câu hỏi đó cho phép xem xét các mã proc so

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

Đầu tiên nếu chi nhánh là khá đơn giản - so sánh nó hai procs là cùng một đối tượng. Thứ hai khó hơn một chút. Nó kiểm tra rằng cả hai procs có cùng một envval, kích thước của iseq (proc thực hiện), kích thước biến cục bộ và so sánh rằng cả hai triển khai đều giống hệt nhau. Điều đó có nghĩa là proc bình đẳng được kiểm tra trên một mức độ cú pháp, không phải trên kết quả proc.

Cho phép mất https://gist.github.com/4611935 Mẫu đầu tiên hoạt động tốt vì số lượng biến cục bộ giống nhau và chuỗi hoạt động giống nhau. Gán 123 cho biến cục bộ. Mẫu thứ hai được coi là không giống nhau vì chuỗi hoạt động khác nhau - bạn gán 123 cho các biến khác nhau.

Nhưng có, so sánh proc khá khó hiểu và đã bị xóa mẫu ruby ​​2.0 Tôi đoán. Bây giờ procs được so sánh như một đối tượng thông thường bởi id của nó.

Các vấn đề liên quan