Memeriksa apakah suatu variabel didefinisikan?

581

Bagaimana saya bisa memeriksa apakah suatu variabel didefinisikan dalam Ruby? Apakah ada issetmetode tipe yang tersedia?

Hanya baca
sumber

Jawaban:

791

Gunakan defined?kata kunci ( dokumentasi ). Ini akan mengembalikan sebuah String dengan jenis item, atau niljika tidak ada.

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

Seperti komentar skalee: "Perlu dicatat bahwa variabel yang ditetapkan ke nol diinisialisasi."

>> n = nil  
>> defined? n
 => "local-variable"
Ricardo Acras
sumber
92
Perlu dicatat bahwa variabel yang diatur ke nil yang diinisialisasi.
skalee
7
Jika Anda ingin mengatur variabel jika tidak ada dan biarkan sendiri jika ada, lihat jawaban @ danmayer (melibatkan ||=operator) di bawah ini.
jrdioko
2
Inilah keanehan lain yang bisa saya lakukan .. Jika Anda mendefinisikan variabel di blok-if yang syaratnya tidak pernah dipenuhi, defined?masih mengembalikan true untuk variabel yang didefinisikan dalam blok itu!
elsurudo
1
Apakah ada metode seperti defined?itu mengembalikan boolean?
stevec
Untuk mengembalikan true / false,!!defined?(object_name)
stevec
91

Ini berguna jika Anda tidak ingin melakukan apa pun jika memang ada, tetapi buat jika itu tidak ada.

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

Ini hanya membuat instance baru sekali. Setelah itu terus mengembalikan var.

danmayer
sumber
9
Omong-omong, ini adalah Ruby yang sangat idiomatis dan sangat tipikal.
jrdioko
38
Hanya saja jangan gunakan ||=dengan nilai boolean, jangan sampai Anda merasakan sakit kebingungan.
Andrew Marshall
6
bersama dengan apa yang dikatakan @AndrewMarshall, hindari idiom ini dengan apa pun yang mungkin kembali niljuga, kecuali jika Anda benar - benar ingin mengevaluasi ekspresi setiap kali dipanggil kembalinil
nzifnab
1
Jika Anda sedang bekerja dengan boolean, dan ingin nilai default untuk menjadi kenyataan jika variabel tidak secara eksplisit diatur ke false, Anda dapat menggunakan konstruksi ini: var = (var or var.nil?)
Tony Zito
1
@ArnaudMeuret Semacam, tidak juga. - Meskipun mungkin tidak identik, ada baiknya membaca jawaban atas pertanyaan itu.
Dana Gugatan Monica
70

Sintaks yang benar untuk pernyataan di atas adalah:

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

mengganti ( var) dengan variabel Anda. Sintaks ini akan mengembalikan nilai benar / salah untuk evaluasi dalam pernyataan if.

Foomip
sumber
11
Itu tidak perlu karena nil bernilai false ketika digunakan dalam ujian
Jerome
Mengapa tidak defined?(var) == nil?
vol7ron
@ vol7ron - Itu sintaks yang benar-benar valid. Menggunakan panggilan untuk .nil?lebih idiomatis, seperti yang mereka katakan. Ini lebih "berorientasi objek" untuk menanyakan objek jika nildaripada menggunakan operator perbandingan. Tidak ada yang sulit dibaca, jadi gunakan yang mana saja yang membantu Anda mengirimkan lebih banyak produk.
juanpaco
Pernyataan apa yang Anda maksud?!? Jangan gunakan jawaban sebagai komentar untuk sesuatu yang lain.
Arnaud Meuret
18

defined?(your_var)akan bekerja. Bergantung pada apa yang Anda lakukan, Anda juga bisa melakukan sesuatuyour_var.nil?

digitalsanctum
sumber
+1 untuk your_var.nil?karena mengembalikan true of false dan jauh lebih baik untuk membaca dan menulis daripada defined? var. Terima kasih untuk ini.
kakubei
28
your_var.nil?akan menghasilkan kesalahan: undefined local variable or method your_varbila tidak ditentukan sebelumnya ...
Gobol
16

Coba "kecuali" daripada "jika"

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
pengguna761856
sumber
Apa yang ditambahkan jawaban ini yang belum diucapkan oleh jawaban lain?
Andrew Grimm
2
Sangat baik menjawab pertanyaan dengan satu cara yang lebih bermanfaat, bukan?
lihat
2
Panduan gaya ruby ​​mengatakan "Mendukung kecuali atas jika untuk kondisi negatif" github.com/bbatsov/ruby-style-guide
ChrisPhoenix
9

Gunakan defined? YourVariable
Keep it simple konyol ..;)

Saqib R.
sumber
8

Ini ada beberapa kode, bukan ilmu roket tapi itu bekerja dengan cukup baik

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

Jelas, kode pewarnaan tidak diperlukan, hanya visualisasi yang bagus dalam contoh mainan ini.

Sardathrion - menentang penyalahgunaan SE
sumber
Mungkin karena nil?ini opsional.
James
8

PERINGATAN Re: Pola Ruby Umum

Ini adalah kunci jawaban: defined?metode. Jawaban yang diterima di atas menggambarkan hal ini dengan sempurna.

Tapi ada hiu, bersembunyi di bawah ombak ...

Pertimbangkan jenis pola ruby ​​umum ini:

 def method1
    @x ||= method2
 end

 def method2
    nil
 end

method2selalu kembali nil. Pertama kali Anda menelepon method1, @xvariabel tidak disetel - karena itu method2akan dijalankan. dan method2akan diatur @xke nil. Itu baik, dan semuanya baik-baik saja. Tapi apa yang terjadi saat Anda menelepon kedua kali method1?

Ingat @x sudah disetel ke nol. But method2masih akan berjalan lagi !! Jika method2 adalah usaha mahal, ini mungkin bukan sesuatu yang Anda inginkan.

Biarkan defined?metode datang ke penyelamatan - dengan solusi ini, kasus tertentu ditangani - gunakan yang berikut:

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

Iblis ada dalam rinciannya: tetapi Anda dapat menghindari hiu yang mengintai itu dengan defined?metode itu.

BKSpurgeon
sumber
Anda sepenuhnya benar, terima kasih telah menyoroti peringatan khusus itu
Kulgar
5

Anda dapat mencoba:

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

Karena mengembalikan boolean.

Bruno Barros
sumber
SyntaxError: compile error (irb):2: syntax error, unexpected $end, expecting kEND
Andrew Grimm
untuk menggunakan unlesspernyataan tampaknya terlalu rumit
johannes
5

Seperti banyak contoh lain menunjukkan Anda tidak benar-benar membutuhkan boolean dari suatu metode untuk membuat pilihan logis dalam ruby. Ini akan menjadi bentuk yang buruk untuk memaksa semuanya ke boolean kecuali Anda benar-benar membutuhkan boolean.

Tetapi jika Anda benar-benar membutuhkan boolean. Gunakan !! (bang bang) atau "falsy falsy mengungkapkan kebenaran".

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

Mengapa biasanya tidak membayar untuk memaksa:

>> (!!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

Berikut adalah contoh di mana itu penting karena bergantung pada paksaan implisit dari nilai boolean untuk representasi stringnya.

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

Harus disebutkan bahwa menggunakan defineduntuk memeriksa apakah bidang tertentu diatur dalam hash mungkin berperilaku tak terduga:

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

Sintaksnya benar di sini, tetapi defined? var['unknown']akan dievaluasi ke string "method", sehingga ifblok akan dieksekusi

sunting: Notasi yang benar untuk memeriksa apakah kunci ada dalam hash adalah:

if var.key?('unknown')
lknknecht
sumber
2

Harap perhatikan perbedaan antara "terdefinisi" dan "ditugaskan".

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

x didefinisikan meskipun tidak pernah ditugaskan!

Robert Klemme
sumber
Ini adalah sesuatu yang baru saja saya temui. Saya mengharapkan NameError Exception: undefined local variable or method, dan bingung ketika satu-satunya penugasan / penyebutan variabel berada di blok if yang tidak terkena.
Paul Pettengill
0

Selain itu, Anda dapat memeriksa apakah itu didefinisikan dalam string melalui interpolasi, jika Anda kode:

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

Sistem akan memberi tahu Anda jenisnya jika sudah ditentukan. Jika tidak didefinisikan, itu hanya akan mengembalikan peringatan yang mengatakan variabel tidak diinisialisasi.

Semoga ini membantu! :)

Elliott
sumber
0

defined?bagus, tetapi jika Anda berada di lingkungan Rails Anda juga dapat menggunakan try, terutama dalam kasus di mana Anda ingin memeriksa nama variabel dinamis:

foo = 1
my_foo = "foo"
my_bar = "bar"
try(:foo)        # => 1
try(:bar)        # => nil
try(my_foo)      # => 1
try(my_bar)      # => nil
John Donner
sumber