ChatGPT解决这个技术问题 Extra ChatGPT

Checking if a variable is defined?

How can I check whether a variable is defined in Ruby? Is there an isset-type method available?


a
akuhn

Use the defined? keyword (documentation). It will return a String with the kind of the item, or nil if it doesn’t exist.

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

As skalee commented: "It is worth noting that variable which is set to nil is initialized."

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

It is worth noting that variable which is set to nil is initialized.
If you want to set a variable if it doesn't exist and leave it alone if it does, see @danmayer's answer (involving the ||= operator) below.
Here's another oddity I can into.. If you define a variable in an if-block for which the condition is never met, defined? still returns true for a variable defined within that block!
Is there a method like defined? that returns boolean?
To return true/false, !!defined?(object_name)
A
Arnaud Meuret

This is useful if you want to do nothing if it does exist but create it if it doesn't exist.

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

This only creates the new instance once. After that it just keeps returning the var.


This is very idiomatic Ruby too and very typical, by the way.
Just don't use ||= with boolean values, lest you feel the pain of confusion.
along with what @AndrewMarshall said, avoid this idiom with anything that might return nil as well unless you really want to evaluate the expression every time it's called when it does return nil
If you are working with booleans, and want the default value to be true if the variable wasn't explicitly set to false, you can use this construction: var = (var or var.nil?)
@ArnaudMeuret Sort of, not really. -- while it may not seem identical, it's worth reading the answers on that question.
T
True Soft

The correct syntax for the above statement is:

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

substituting (var) with your variable. This syntax will return a true/false value for evaluation in the if statement.


That's not necessary as nil evaluates to false when used in a test
Why not defined?(var) == nil ?
@vol7ron - That is perfectly valid syntax. Using the call to .nil? is more idiomatic, as they say. It's more "object-oriented" to ask an object if it nil than to use a comparison operator. Neither is difficult to read, so use whichever one helps you ship more product.
Which statement are you refering to ?!? Don't use an answer as a comment to something else.
d
digitalsanctum

defined?(your_var) will work. Depending on what you're doing you can also do something like your_var.nil?


+1 for your_var.nil? because it returns true of false and is much nicer to read and write than defined? var. Thanks for this.
your_var.nil? will result in error : undefined local variable or method your_var when not defined before...
T
Taymon

Try "unless" instead of "if"

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

What does this answer add that hasn't been said by the other answers?
It very nicely answers the question in one more useful way, doesn't it?
The ruby style guide says "Favor unless over if for negative conditions" github.com/bbatsov/ruby-style-guide
B
BenKoshy

WARNING Re: A Common Ruby Pattern

This is the key answer: the defined? method. The accepted answer above illustrates this perfectly.

But there is a shark, lurking beneath the waves...

Consider this common ruby pattern:

 def method1
    @x ||= method2
 end

 def method2
    nil
 end

method2 always returns nil. The first time you call method1, the @x variable is not set - therefore method2 will be run. and method2 will set @x to nil.

But what happens the second time you call method1?

Remember @x has already been set to nil. But method2 will still be run again!! If method2 is a costly undertaking this might not be something that you want.

Let the defined? method come to the rescue:

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

As with most things, the devil is in the implementation details.


You are totally right, thank you for highlighting that specific caveat
S
Saqib R.

Use defined? YourVariable
Keep it simple silly .. ;)


S
Sardathrion - against SE abuse

Here is some code, nothing rocket science but it works well enough

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

Clearly, the colouring code is not necessary, just a nice visualation in this toy example.


Presumably because the nil? is optional.
H
Haris Krajina

You can try:

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

Because it returns a boolean.


SyntaxError: compile error (irb):2: syntax error, unexpected $end, expecting kEND
to use an unless statement seems overly complicated
d
donnoman

As many other examples show you don't actually need a boolean from a method to make logical choices in ruby. It would be a poor form to coerce everything to a boolean unless you actually need a boolean.

But if you absolutely need a boolean. Use !! (bang bang) or "falsy falsy reveals the truth".

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

Why it doesn't usually pay to coerce:

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

Here's an example where it matters because it relies on the implicit coercion of the boolean value to its string representation.

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

l
leberknecht

It should be mentioned that using defined to check if a specific field is set in a hash might behave unexpected:

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

The syntax is correct here, but defined? var['unknown'] will be evaluated to the string "method", so the if block will be executed

edit: The correct notation for checking if a key exists in a hash would be:

if var.key?('unknown')

R
Robert Klemme

Please note the distinction between "defined" and "assigned".

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

x is defined even though it is never assigned!


This is something I just came across. I was expecting NameError Exception: undefined local variable or method, and was confused when the only assignment/mention of the variable was in an if block that wasn't getting hit.
J
John Donner

defined? is great, but if you are in a Rails environment you can also use try, especially in cases where you want to check a dynamic variable name:

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

this is exactly what I was looking for. I need the value if the var exists.Thanks!
E
Elliott

Also, you can check if it's defined while in a string via interpolation, if you code:

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

The system will tell you the type if it is defined. If it is not defined it will just return a warning saying the variable is not initialized.

Hope this helps! :)


s
stevec

Leaving an incredibly simple example in case it helps.

When variable doesn't exist:

if defined? a then "hi" end
# => nil

When variable does exist:

a = 2
if defined? a then "hi" end
# => "hi"