检查是否定义了变量?


581

如何检查Ruby中是否定义了变量?有没有isset可用的-type方法?

Answers:


791

使用defined?关键字(documentation)。它将返回带有项目类型或nil不存在的字符串。

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

正如skalee所说:“值得注意的是,设置为nil的变量已初始化。”

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

92
值得注意的是,设置为的变量nil 初始化。
skalee 2011年

7
如果要设置一个不存在的变量,如果要设置一个变量,请不要理会,请参见下面的@danmayer答案(涉及||=运算符)。
jrdioko

2
这是我可能遇到的另一个奇怪问题。如果您在if块中定义一个永不满足条件的变量,则对于defined?在该块中定义的变量仍然返回true!
elsurudo '16

1
有没有这样的方法defined?返回布尔值?
stevec '19

要返回真/假,!!defined?(object_name)
stevec '19

91

如果您希望不执行任何操作但不执行任何操作,则可以创建该控件。

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

这只会创建一次新实例。之后,它只会不断返回var。


9
顺便说一句,这也是非常习惯的Ruby,而且非常典型。
jrdioko

38
只是不要||=与布尔值一起使用,以免您感到困惑的痛苦。
安德鲁·马歇尔

6
连同@AndrewMarshall所说的一样,请避免将此成语与可能返回的任何事物nil同时使用,除非您真的想在表达式每次返回时都对其求值nil
nzifnab 2012年

1
如果你:与布尔合作,并希望如果变量没有明确设置为默认值false是真实的,你可以使用这种结构 var = (var or var.nil?)
托尼·齐托

1
@ArnaudMeuret有点,不是真的。-尽管看起来可能并不完全相同,但值得阅读有关该问题的答案。
基金莫妮卡的诉讼

70

以上语句的正确语法为:

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

用(var)替换您的变量。此语法将在if语句中返回true / false值以进行评估。


11
不需要,因为nil在测试中使用时评估为假
Jerome 2012年

为什么不defined?(var) == nil呢?
vol7ron 2013年

@ vol7ron-这是完全有效的语法。.nil?正如他们所说,使用to 更为习惯。问一个对象是否nil比使用比较运算符更“面向对象” 。两者都不难阅读,因此请使用任何一种都可以帮助您运送更多产品。
juanpaco

您指的是哪句话?不要将答案用作对其他事物的评论。
2014年

18

defined?(your_var)将工作。根据您的操作,您还可以执行类似的操作your_var.nil?


+1是your_var.nil?因为它返回true为false,并且比读和写要好得多defined? var。谢谢你
kakubei

28
your_var.nil?会导致错误:undefined local variable or method your_var如果在之前未定义...
Gobol 2013年

16

尝试“除非”,而不是“如果”

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

这个答案增加了其他答案未曾说过的内容?
安德鲁·格林

2
它以一种更有用的方式很好地回答了这个问题,不是吗?
请看

2
红宝石风格指南说:“除非有不利条件,否则除非有理由
否则请收藏


8

这是一些代码,没什么火箭科学,但效果很好

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

显然,着色代码不是必需的,只是此玩具示例中的漂亮外观。


大概是因为nil?可选。
2012年

8

警告:常见的Ruby模式

这是关键的答案:defined?方法。上面接受的答案很好地说明了这一点。

但是有一条鲨鱼潜伏在海浪下...

考虑这种常见的红宝石图案:

 def method1
    @x ||= method2
 end

 def method2
    nil
 end

method2总是返回nil。第一次调用时method1,该@x变量未设置-因此method2将运行。并且method2将设置@xnil。很好,一切都很好。但是第二次打电话时会发生什么method1呢?

记住@x已经设置为nil。But method2仍然会再次运行!如果method2是一项昂贵的工作,那么您可能不需要这样做。

让该defined?方法来解决这个问题,使用以下解决方案:

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

细节在于魔鬼:但是您可以使用该defined?方法来逃避潜伏的鲨鱼。


您完全正确,感谢您强调了这一特定警告
卡尔加


5

如许多其他示例所示,您实际上不需要从方法中获取布尔值就可以在ruby中进行逻辑选择。除非您确实需要布尔值,否则将所有内容强制为布尔值将是一种糟糕的形式。

但是,如果您绝对需要布尔值。采用 !!(bang bang)或“ falsy falsy揭示了事实”。

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

为什么通常不花钱去胁迫:

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

这是一个重要的示例,因为它依赖于布尔值对其字符串表示形式的隐式强制。

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

3

应该提到的是,defined用于检查哈希中是否设置了特定字段的行为可能会发生意外:

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

语法在这里是正确的,但是defined? var['unknown']将被评估为string "method",因此if将执行该块

编辑:检查哈希中是否存在键的正确表示法是:

if var.key?('unknown')

2

请注意“已定义”和“已分配”之间的区别。

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

即使从未定义x,它也已定义!


这是我刚遇到的。我期待中NameError Exception: undefined local variable or method,并且当变量的唯一赋值/提及是在if块中没有被击中时感到困惑。
Paul Pettengill

0

另外,如果您编写代码,则可以通过插值检查是否在字符串中定义了它:

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

系统会告诉您类型是否已定义。如果未定义,它将仅返回警告,指出该变量未初始化。

希望这可以帮助!:)


0

defined?很棒,但是如果您在Rails环境中,也可以使用try,尤其是在要检查动态变量名称的情况下:

foo = 1
my_foo = "foo"
my_bar = "bar"
try(:foo)        # => 1
try(:bar)        # => nil
try(my_foo)      # => 1
try(my_bar)      # => nil
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.