2016-03-08 13 views
6

(Câu hỏi đã được đăng tại Ruby Forum, nhưng không gợi ra bất kỳ câu trả lời nào ở đó).Phương pháp thể hiện được thêm động không thể truy cập biến lớp

Đây là mã của tôi:

class MC 
    def initialize 
    @x = 5 
    @@y = 6 
    end 

    def f 
    puts @x 
    puts @@y 
    end 
end 

m = MC.new 
m.f 

m.f sản xuất sản lượng dự kiến ​​mà không có lỗi:

5 
6 

Nhưng điều này:

def m.g 
    puts @x 
    puts @@y 
end 

m.g 

sản xuất:

5 
warning: class variable access from toplevel 
NameError: uninitialized class variable @@y in Object 

Tại sao tôi có thể truy cập @@y từ f, nhưng không phải từ g?

Đề cập đến toplevelObject trong cảnh báo và thông báo lỗi gây nhầm lẫn với tôi.

@x được in dưới dạng 5, vì vậy môi trường của nó là MC. Điều này loại trừ khả năng @x@@y trong định nghĩa m.g tham chiếu đến môi trường phức tạp (Object) thay vì MC.

Tại sao tôi nhận được thông báo lỗi?

+3

Điều này đã được hỏi trước: http://stackoverflow.com/q/24510948/477037 – Stefan

+1

@Stefan: True. Thật không may, không có lời giải thích tốt có là tốt. –

Trả lời

4

Bạn không tạo g trong lớp MC nhưng trong m lớp đơn (a.k.a. eigenclass).

Đây là lớp dành riêng cho đối tượng m để lưu trữ các phương thức đơn được xác định chỉ dành cho m.

+0

'lớp << m; đặt class_variable_get (: @@ y); end' hoạt động hoàn hảo. Cũng như 'def m.g; đặt self.class.class_variable_get (: @@ y); kết thúc'. Đó là một chút lạ. – mudasobwa

+0

Lưu ý rằng đây chỉ là một phần của câu trả lời. Lớp singleton là một lớp con của 'MC' (' m.singleton_class.superclass # => MC') và do đó "thấy" '@@ y' (' m.singleton_class.class_variables # => [: @yy] '). Tôi đang thiếu lý do tại sao tra cứu không thành công. –

+0

Tôi đoán đó là trục trặc của trình phân tích cú pháp. – mudasobwa

5

Tất cả các phiên bản dưới đây làm việc:

def m.g; puts self.class.send(:class_eval, '@@y') end 

def m.g; puts self.class.class_variable_get(:@@y) end 

class << m; def g; puts self.class.send(:class_eval, '@@y') end end 

class << m; puts class_variable_get(:@@y) end 

Nhưng những thất bại:

def m.g; puts @@y; end 

class << m; puts class_eval('@@y') end 

tôi sẽ xem xét việc này là một trục trặc ruby ​​phân tích cú pháp.

+0

Lưu ý rằng phương thức '# class'" bỏ qua "lớp singleton và trả về' MC'. Vì vậy, 3 đầu tiên không thực sự đáng ngạc nhiên. Bạn cũng nên thêm các biến thể với 'singleton_class' hiển thị cùng một hành vi. –

+1

Có vẻ như các quy tắc tra cứu liên tục cũng áp dụng cho các biến lớp, tức là chúng được lexically scoped. – Stefan

+0

@undur_gongor 'lớp << m' là các biến thể với' singleton_class'. – mudasobwa

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