2012-01-02 24 views
7

Tôi đã thực hành một số chương trình siêu lập trình Ruby gần đây, và đã tự hỏi về assigning anonymous classes to constants.Có móc nào khi các lớp ẩn danh được gán cho một hằng số không?

Trong Ruby, nó có thể tạo ra một lớp vô danh như sau:

anonymous_class = Class.new # => #<Class:0x007f9c5afb21d0> 

trường hợp mới của lớp này có thể được tạo ra:

an_instance = anonymous_class.new # => #<#<Class:0x007f9c5afb21d0>:0x007f9c5afb0330> 

Bây giờ, khi lớp vô danh được gán cho một hằng số, lớp học hiện có tên riêng:

Foo = anonymous_class # => Foo 

Và ví dụ đã tạo trước đó bây giờ cũng là một thể hiện của lớp đó:

an_instance # => #<Foo:0x007f9c5afb0330> 

Câu hỏi của tôi: Có một phương pháp móc cho thời điểm này khi một lớp vô danh được gán cho một hằng số?

Có rất nhiều hooks methods trong Ruby, nhưng tôi không thể tìm thấy cái này.

+0

Câu hỏi rất thú vị. –

+1

AFAIK vẫn không có móc cho các bài tập thay đổi, không đổi hoặc bằng cách khác ([xem ở đây cho cùng một câu hỏi một thời gian dài trước đây] (http://www.ruby-forum.com/topic/65720)). Globals, vâng. –

Trả lời

6

Chúng ta hãy xem cách phân bổ liên tục hoạt động nội bộ. Mã sau được trích xuất từ ​​một tarball nguồn của ruby-1.9.3-p0. Đầu tiên chúng ta nhìn vào định nghĩa của hướng dẫn VM setconstant (được sử dụng để gán hằng):

# /insns.def, line 239 
DEFINE_INSN 
setconstant 
(ID id) 
(VALUE val, VALUE cbase) 
() 
{ 
    vm_check_if_namespace(cbase); 
    rb_const_set(cbase, id, val); 
    INC_VM_STATE_VERSION(); 
} 

Không có cơ hội để đặt một cái móc ở vm_check_if_namespace hoặc INC_VM_STATE_VERSION đây. Vì vậy, chúng ta nhìn vào rb_const_set (variable.c: 1886), chức năng đó được gọi là mỗi lần một hằng số được gán:

# /variable.c, line 1886 
void 
rb_const_set(VALUE klass, ID id, VALUE val) 
{ 
    rb_const_entry_t *ce; 
    VALUE visibility = CONST_PUBLIC; 

    # ... 

    check_before_mod_set(klass, id, val, "constant"); 
    if (!RCLASS_CONST_TBL(klass)) { 
     RCLASS_CONST_TBL(klass) = st_init_numtable(); 
    } 
    else { 
     # [snip], won't be called on first assignment 
    } 

    rb_vm_change_state(); 

    ce = ALLOC(rb_const_entry_t); 
    ce->flag = (rb_const_flag_t)visibility; 
    ce->value = val; 

    st_insert(RCLASS_CONST_TBL(klass), (st_data_t)id, (st_data_t)ce); 
} 

Tôi đã gỡ bỏ tất cả các mã mà thậm chí còn không được gọi là lần đầu tiên một hằng số được giao bên trong một mô-đun. Sau đó tôi nhìn vào tất cả các chức năng được gọi bởi cái này và không tìm thấy một điểm duy nhất mà chúng ta có thể đặt một cái móc từ mã Ruby. Điều này có nghĩa là sự thật khó khăn là, trừ khi tôi bỏ lỡ một cái gì đó, rằng có không có cách để móc một nhiệm vụ liên tục (ít nhất là trong MRI).

Cập nhật

Để làm rõ: Lớp vô danh không không kỳ diệu có được một tên mới ngay khi nó được gán (như đã nói một cách chính xác trong câu trả lời của Andrew). Thay vào đó, tên hằng số cùng với ID đối tượng của lớp được lưu trữ trong bảng tra cứu nội bộ của Ruby. Nếu, sau đó, tên của lớp được yêu cầu, bây giờ nó có thể được giải quyết thành một tên thích hợp (và không chỉ là Class:0xXXXXXXXX...).Vì vậy, tốt nhất bạn có thể làm để phản ứng với nhiệm vụ này là kiểm tra name của lớp trong một vòng lặp của một chuỗi công nhân nền cho đến khi nó không phải là nil (mà là một sự lãng phí lớn các nguồn lực, IMHO).

+0

Cảm ơn câu trả lời rất mở rộng. Để làm cho nó hoàn thành, làm thế nào bạn tìm thấy tham chiếu này để 'setconstant'? Các tài liệu trong nguồn ('insns.def') không phải là rất rõ ràng với tôi:" set hằng số biến id.Nếu klass là Qfalse, hằng số có thể truy cập trong phạm vi này. Nếu klass là Qnil, thiết lập mức cao nhất liên tục. nếu không, hãy đặt hằng số theo lớp klass hoặc mô-đun. " Mã này có thực sự được sử dụng để gán các hằng số cho các cá thể lớp (ẩn danh) không? – rdvdijk

+0

@rdvdijk: Tôi đoán và đã xác minh nó bằng 'printf'. –

+0

Tôi đã xem xét mã nguồn mà bạn tham chiếu ở đây và hiểu ý nghĩa của mã bạn đã dán. Tuy nhiên, nó không trả lời đầy đủ câu hỏi của tôi. Mã này cho thấy việc xử lý việc gán các hằng số và mã này không có sẵn móc. Tuy nhiên, điều này không giải thích khi nào và ở đâu lớp ẩn danh phát hiện ra tên mới của nó. Theo câu trả lời của Andrew Grimm, có vẻ như phương thức 'classname' và mã liên quan tra cứu hằng số trong cả hai' RCLASS_CONST_TBL' hoặc 'rb_class_tbl', đúng không? – rdvdijk

0

Các lớp ẩn danh không thực sự nhận được tên của chúng khi chúng được gán cho một hằng số. Họ thực sự nhận được nó khi họ tiếp theo hỏi tên của họ là gì.

Tôi sẽ cố gắng tìm một tham chiếu cho việc này. Chỉnh sửa: Không thể tìm thấy một, xin lỗi.

+0

Chìa khóa là hàm 'rb_class_name' được định nghĩa trong' biến.c: 305' (ruby-1.9.3-p0) và các hàm được gọi bởi nó (đặc biệt là 'find_class_path', sử dụng bản đồ' RCLASS_CONST_TBL' để kiểm tra xem lớp học bị ràng buộc với một cái tên, ít nhất là nếu tôi giải thích nó là chính xác). –

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