2012-02-22 30 views
12
class String 
    def hello 
    "world" 
    end 
end 

String.class_eval { 
    def world 
    "hello" 
    end 
} 

"a".world 
=> "hello" 
"b".hello 
=> "world" 

Chúng dường như làm điều tương tự - thêm phương thức vào lớp hiện có. Vậy sự khác biệt là gì?khỉ vá vs class_eval?

Trả lời

12

Với class_eval bạn có thể làm những việc năng động hơn:

>> met = "hello" #=> "hello" 
>> String.class_eval "def #{met} ; 'hello' ; end" #=> nil 
>> "foo".hello #=> "hello" 
11

class_eval làm khái niệm lớp mở lại (hoặc khỉ vá). Có nhiều sự khác biệt về cú pháp. Nếu bạn chuyển chuỗi tới class_eval (như trong ví dụ của Michael), bạn có cùng một cú pháp trong chuỗi như trong class String; ... end. Nếu bạn vượt qua khối: String.class_eval { ... } nó so sánh như sau:

  • bên trong khối class_eval biến cục bộ bên ngoài có thể nhìn thấy
  • bên trong lớp mở cửa trở lại các biến cục bộ bên ngoài không nhìn thấy được
  • bên class_eval bạn không thể gán hằng số và biến lớp scoped đến lớp
  • bên trong lớp mở cửa trở lại bạn cÓ tHỂ

Nó sẽ là thú vị khi biết được sự khác biệt khác

0

Câu trả lời khác là tốt. Bạn muốn thêm rằng class_eval có thể được sử dụng khi bạn muốn tham chiếu lớp không phải bởi hằng số của nó hoặc để vá đối tượng cụ thể.

ví dụ:

huh = String 
class huh 
end 
SyntaxError: (eval):2: class/module name must be CONSTANT 

huh.class_eval <<-eof 
def mamma 
puts :papa 
end 
eof 

"asdff".mamma 
=> papa 

Bạn có thể sử dụng class_eval để vá đối tượng cụ thể mà không ảnh hưởng đến toàn bộ lớp gốc.

obj = "asd" 
obj.singleton_class.class_eval <<-eof 
def asd 
puts "gah" 
end 
undef_method :some_method 

Trên đây là giống như:

class << obj 
    ... 
end 

instance_eval sẽ có hành vi hơi khác nhau bởi một số cách sử dụng.

Tôi tìm thấy câu hỏi này và câu trả lời thú vị: How to monkey patch a ruby class inside a method

Cũng có những câu hỏi về instance_eval vs class_eval nhưng tôi không có một liên kết có ích.

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