Memeriksa apakah suatu variabel didefinisikan?


581

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

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"

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.


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.


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?


+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

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 ..;)


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.


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.


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.


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

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')

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!


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! :)


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
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.