2010-10-26 13 views
12

Cùng trong Ruby 1.8.7 và 1.9.2:Trong Ruby, tại sao sau khi bắt đầu irb, foo.nil? nói lỗi không xác định và @ foo.nil? cho "true" và @@ wah.nil? lại đưa ra lỗi?

$ irb 

ruby-1.8.7-p302 > foo.nil? 
NameError: undefined local variable or method `foo' for #<Object:0x3794c> 
    from (irb):1 

ruby-1.8.7-p302 > @bar.nil? 
=> true 

ruby-1.8.7-p302 > @@wah.nil? 
NameError: uninitialized class variable @@wah in Object 
    from (irb):3 

tại sao biến dụ đối xử khác biệt so với một biến địa phương và lớp học?

Trả lời

17

Trong Ruby, hầu hết các biến chưa được khởi tạo hoặc thậm chí không tồn tại được đánh giá là nil. Điều này đúng cho các biến địa phương, các biến dụ và các biến toàn cầu:

defined? foo  #=> nil 
local_variables #=> [] 
if false 
    foo = 42 
end 
defined? foo  #=> 'local-variable' 
local_variables #=> [:foo] 
foo    #=> nil 
foo.nil?   #=> true 

defined? @bar  #=> nil 
instance_variables #=> [] 
@bar    #=> nil 
@bar.nil?   #=> true 
# warning: instance variable @bar not initialized 

defined? $baz  #=> nil 
$baz    #=> nil 
# warning: global variable `$baz' not initialized 
$baz.nil?   #=> true 
# warning: global variable `$baz' not initialized 

Đó là, tuy nhiên, không đúng sự thật cho các biến hệ thống phân cấp lớp và các hằng số:

defined? @@wah  #=> nil 
@@wah 
# NameError: uninitialized class variable @@wah in Object 

defined? QUUX  #=> nil 
QUUX 
# NameError: uninitialized constant Object::QUUX 

Đây là một cá trích đỏ:

defined? fnord  #=> nil 
local_variables #=> [] 
fnord 
# NameError: undefined local variable or method `fnord' for main:Object 

Lý do tại sao bạn nhận được lỗi ở đây là không phải rằng các biến cục bộ được đơn vị hóa không đánh giá là nil, đó là mũ fnord không rõ ràng: có thể là hoặc thông báo ít đối số gửi tới người nhận mặc định (tức là tương đương với self.fnord()) hoặc quyền truy cập vào biến cục bộ fnord.

Để disambiguate đó, bạn cần phải thêm một máy thu hoặc một danh sách đối số (ngay cả khi có sản phẩm nào) nói của Ruby rằng đó là một gửi thông điệp:

self.fnord 
# NoMethodError: undefined method `fnord' for main:Object 
fnord() 
# NoMethodError: undefined method `fnord' for main:Object 

hoặc chắc chắn rằng phân tích cú pháp (không người đánh giá) phân tích (không thực thi) một bài tập trước khi sử dụng, để nói của Ruby rằng nó là một biến cục bộ:

if false 
    fnord = 42 
end 
fnord    #=> nil 

tại sao biến mẫu được xử lý khác với biến cục bộ và lớp?

Thực tế là không. Nó được xử lý giống như một biến cục bộ. Biến phân cấp lớp là biến hoạt động khác nhau, các biến cục bộ, biến mẫu và biến toàn cầu đều hoạt động giống nhau.

có các lý do khác & hellip; các biến lớp không thể hoạt động như vậy?

Tôi không biết. Ví dụ, biến rất tiện lợi, vì không giống như Java, ví dụ, trong đó các biến mẫu được khai báo trong định nghĩa lớp und do đó luôn luôn tồn tại cho mọi cá thể của lớp, trong Ruby, các biến mẫu không được khai báo ở bất kỳ đâu. Họ chỉ kỳ diệu mọc vào sự tồn tại, ngay sau khi họ được phân công. Vì các biến mẫu không nhất thiết được đảm bảo tồn tại, các phương thức viết sử dụng các biến mẫu sẽ là một nỗi đau nếu chúng ném các ngoại lệ.

Tại sao các biến phân cấp lớp khác nhau, tôi không có ý tưởng. Có lẽ bởi vì không ai sử dụng chúng dù sao, hoặc vì chúng thường có xu hướng được khởi tạo trong phần thân của lớp và đơn giản là không được truy cập khi chúng không được khởi tạo.