Kiểm tra nếu một biến được xác định?


581

Làm cách nào để kiểm tra xem một biến có được định nghĩa trong Ruby không? Có một issetphương pháp -type có sẵn?

Câu trả lời:


791

Sử dụng defined?từ khóa ( tài liệu ). Nó sẽ trả về một Chuỗi với loại vật phẩm hoặc nilnếu nó không tồn tại.

>> a = 1
 => 1
>> defined? a
 => "local-variable"
>> defined? b
 => nil
>> defined? nil
 => "nil"
>> defined? String
 => "constant"
>> defined? 1
 => "expression"

Như skalee nhận xét: "Điều đáng chú ý là biến được đặt thành nil được khởi tạo."

>> n = nil  
>> defined? n
 => "local-variable"

92
Điều đáng chú ý là biến mà được thiết lập để nil được khởi tạo.
skalee

7
Nếu bạn muốn đặt một biến nếu nó không tồn tại và để nó một mình nếu có, hãy xem câu trả lời của @ danmayer's (liên quan đến ||=toán tử) bên dưới.
jrdioko

2
Đây là một điều kỳ quặc khác mà tôi có thể tham gia .. Nếu bạn xác định một biến trong khối if mà điều kiện không bao giờ được đáp ứng, defined?vẫn trả về true cho một biến được xác định trong khối đó!
elsurudo

1
Có một phương pháp như thế defined?trả về boolean?
stevec

Để trả về đúng / sai,!!defined?(object_name)
stevec

91

Điều này hữu ích nếu bạn không muốn làm gì nếu nó tồn tại nhưng tạo ra nó nếu nó không tồn tại.

def get_var
  @var ||= SomeClass.new()
end

Điều này chỉ tạo ra trường hợp mới một lần. Sau đó, nó tiếp tục trả về var.


9
Nhân tiện, đây cũng là một thành ngữ rất điển hình và rất điển hình.
jrdioko

38
Chỉ không sử dụng ||=với các giá trị boolean, kẻo bạn cảm thấy đau đớn của sự nhầm lẫn.
Andrew Marshall

6
cùng với những gì @AndrewMarshall đã nói, hãy tránh thành ngữ này với bất cứ điều gì có thể trở lại niltrừ khi bạn thực sự muốn đánh giá biểu thức mỗi khi nó được gọi khi nó trở lạinil
nzifnab

1
Nếu bạn đang làm việc với booleans và muốn giá trị mặc định là true nếu biến không được đặt rõ ràng thành false, bạn có thể sử dụng cấu trúc này: var = (var or var.nil?)
Tony Zito

1
@ArnaudMeuret Sắp xếp, không thực sự. - trong khi nó có vẻ không giống nhau, thật đáng để đọc câu trả lời cho câu hỏi đó.
Vụ kiện của Quỹ Monica

70

Cú pháp đúng cho câu lệnh trên là:

if (defined?(var)).nil? # will now return true or false
 print "var is not defined\n".color(:red)
else
 print "var is defined\n".color(:green)
end

thay thế ( var) bằng biến của bạn. Cú pháp này sẽ trả về giá trị đúng / sai để đánh giá trong câu lệnh if.


11
Điều đó không cần thiết vì con số không được đánh giá là sai khi được sử dụng trong bài kiểm tra
Jerome

Tại sao không defined?(var) == nil?
vol7ron

@ vol7ron - Đó là cú pháp hoàn toàn hợp lệ. Sử dụng cuộc gọi đến .nil?là thành ngữ hơn, như họ nói. Đó là "hướng đối tượng" nhiều hơn để hỏi một đối tượng nếu nó nilhơn là sử dụng một toán tử so sánh. Không khó đọc, vì vậy hãy sử dụng cái nào giúp bạn vận chuyển nhiều sản phẩm hơn.
juanpaco

Câu nào bạn muốn nói đến?!? Đừng sử dụng một câu trả lời như một bình luận cho một cái gì đó khác.
Arnaud Meuret

18

defined?(your_var)sẽ làm việc. Tùy thuộc vào những gì bạn đang làm, bạn cũng có thể làm một cái gì đó nhưyour_var.nil?


+1 your_var.nil?vì nó trả về true của false và đọc và viết tốt hơn nhiều defined? var. Cám ơn vì cái này.
kakubei

28
your_var.nil?sẽ dẫn đến lỗi: undefined local variable or method your_varkhi không được xác định trước ...
Gobol

16

Hãy thử "trừ khi" thay vì "nếu"

a = "apple"
# Note that b is not declared
c = nil

unless defined? a
    puts "a is not defined"
end

unless defined? b
    puts "b is not defined"
end

unless defined? c
    puts "c is not defined"
end

Câu trả lời này thêm gì mà chưa được nói bởi các câu trả lời khác?
Andrew Grimm

2
Nó rất hay trả lời câu hỏi theo một cách hữu ích hơn, phải không?
nhìn

2
Hướng dẫn về phong cách ruby ​​nói "Ưu tiên trừ khi có điều kiện tiêu cực" github.com/bbatsov/ruby-style-guide
ChrisPhoenix

9

Sử dụng defined? YourVariable
Giữ cho nó đơn giản ngớ ngẩn ..;)


8

Đây là một số mã, không có gì khoa học tên lửa nhưng nó hoạt động đủ tốt

require 'rubygems'
require 'rainbow'
if defined?(var).nil?  # .nil? is optional but might make for clearer intent.
 print "var is not defined\n".color(:red)
else
 print "car is defined\n".color(:green)
end

Rõ ràng, mã màu là không cần thiết, chỉ là một hình ảnh đẹp trong ví dụ đồ chơi này.


Có lẽ bởi vì nil?là tùy chọn.
James

8

Re: Một mẫu Ruby thông dụng

Đây là câu trả lời chính: defined?phương pháp. Câu trả lời được chấp nhận ở trên minh họa điều này một cách hoàn hảo.

Nhưng có một con cá mập, ẩn mình dưới những con sóng ...

Xem xét loại mô hình ruby ​​phổ biến này:

 def method1
    @x ||= method2
 end

 def method2
    nil
 end

method2luôn luôn trở về nil. Lần đầu tiên bạn gọi method1, @xbiến không được đặt - do đó method2sẽ được chạy. và method2sẽ đặt @xthành nil. Điều đó là tốt, và tất cả tốt và tốt. Nhưng điều gì xảy ra lần thứ hai bạn gọi method1?

Hãy nhớ @x đã được đặt thành nil. But method2vẫn sẽ được chạy lại !! Nếu phương thức 2 là một công việc tốn kém thì đây có thể không phải là điều bạn muốn.

Hãy để defined?phương pháp đến giải cứu - với giải pháp này, trường hợp cụ thể đó được xử lý - sử dụng như sau:

  def method1
    return @x if defined? @x
    @x = method2
  end

Ma quỷ nằm trong các chi tiết: nhưng bạn có thể trốn tránh con cá mập ẩn nấp đó bằng defined?phương pháp.


Bạn hoàn toàn đúng, cảm ơn bạn đã làm nổi bật sự cảnh báo cụ thể đó
Kulgar

5

Bạn co thể thử:

unless defined?(var)
  #ruby code goes here
end
=> true

Bởi vì nó trả về một boolean.


SyntaxError: compile error (irb):2: syntax error, unexpected $end, expecting kEND
Andrew Grimm

sử dụng một unlesstuyên bố dường như quá phức tạp
johannes

5

Như nhiều ví dụ khác cho thấy bạn không thực sự cần một boolean từ một phương thức để đưa ra các lựa chọn hợp lý trong ruby. Nó sẽ là một hình thức nghèo nàn để ép buộc mọi thứ đối với một boolean trừ khi bạn thực sự cần một boolean.

Nhưng nếu bạn thực sự cần một boolean. Sử dụng !! (bang bang) hoặc "falsy falsy tiết lộ sự thật".

 irb
>> a = nil
=> nil
>> defined?(a)
=> "local-variable"
>> defined?(b)
=> nil
>> !!defined?(a)
=> true
>> !!defined?(b)
=> false

Tại sao nó thường không trả tiền để ép buộc:

>> (!!defined?(a) ? "var is defined".colorize(:green) : "var is not defined".colorize(:red)) == (defined?(a) ? "var is defined".colorize(:green) : "var is not defined".colorize(:red))
=> true

Đây là một ví dụ mà nó quan trọng bởi vì nó dựa vào sự ép buộc ngầm định của giá trị boolean đối với biểu diễn chuỗi của nó.

>> puts "var is defined? #{!!defined?(a)} vs #{defined?(a)}"
var is defined? true vs local-variable
=> nil

3

Cần đề cập rằng việc sử dụng definedđể kiểm tra xem một trường cụ thể được đặt trong hàm băm có thể hoạt động không mong muốn:

var = {}
if defined? var['unknown']
  puts 'this is unexpected'
end
# will output "this is unexpected"

Cú pháp đúng ở đây, nhưng defined? var['unknown']sẽ được đánh giá theo chuỗi "method", vì vậyif khối sẽ được thực thi

chỉnh sửa: Ký hiệu chính xác để kiểm tra xem khóa có tồn tại trong hàm băm không:

if var.key?('unknown')

2

Xin lưu ý phân biệt giữa "được xác định" và "được chỉ định".

$ ruby -e 'def f; if 1>2; x=99; end;p x, defined? x; end;f'
nil
"local-variable"

x được định nghĩa ngay cả khi nó không bao giờ được gán!


Đây là một cái gì đó tôi vừa đi qua. Tôi đã mong đợi NameError Exception: undefined local variable or methodvà bối rối khi chỉ định / đề cập đến biến duy nhất là trong một khối nếu không bị tấn công.
Paul Pettengill

0

Ngoài ra, bạn có thể kiểm tra xem nó có được xác định khi ở trong chuỗi thông qua phép nội suy hay không, nếu bạn viết mã:

puts "Is array1 defined and what type is it? #{defined?(@array1)}"

Hệ thống sẽ cho bạn biết loại nếu nó được xác định. Nếu nó không được xác định, nó sẽ chỉ trả về một cảnh báo cho biết biến không được khởi tạo.

Hi vọng điêu nay co ich! :)


0

defined?là tuyệt vời, nhưng nếu bạn ở trong môi trường Rails, bạn cũng có thể sử dụng try, đặc biệt trong trường hợp bạn muốn kiểm tra tên biến động:

foo = 1
my_foo = "foo"
my_bar = "bar"
try(:foo)        # => 1
try(:bar)        # => nil
try(my_foo)      # => 1
try(my_bar)      # => nil
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.