変数が定義されているかどうかを確認していますか?


581

Rubyで変数が定義されているかどうかを確認するにはどうすればよいですか?そこにあるisset型の方法が利用可能?

回答:


791

defined?キーワード(documentation)を使用します。アイテムの種類、またはnil存在しない場合はStringを返します。

>> 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 初期化されていることは注目に値します。
スケーリー

7
存在しない場合に変数を設定し、存在する場合はそのままにする場合は、以下の@danmayerの回答(||=演算子を含む)を参照してください。
jrdioko

2
もう1つの奇妙な点があります。条件が満たされないifブロックでdefined?変数を定義しても、そのブロック内で定義されている変数に対してtrueが返されます。
elsurudo

1
defined?そのようなメソッドはブール値を返しますか?
stevec

真/偽を返すには、!!defined?(object_name)
stevec

91

これは、存在する場合は何もせず、存在しない場合は作成する場合に便利です。

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

これにより、新しいインスタンスが1回だけ作成されます。その後、varを返し続けます。


9
ちなみに、これも非常に慣用的なRubyであり、非常に典型的です。
jrdioko

38
||=混乱の痛みを感じないように、ブール値では使用しないでください。
アンドリューマーシャル

6
@AndrewMarshallが言ったことに加えて、返されるときに呼び出されるたびに式nil実際に評価したくない場合を除いて、このイディオムを返す可能性があるものは避けてくださいnil
nzifnab

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
テストに使用した場合にはfalseにnilに評価される必要はありません
ジェローム

なんでdefined?(var) == nil
vol7ron 2013

@ vol7ron-これは完全に有効な構文です。.nil?彼らが言うように、呼び出しを使用することはより慣用的です。nil比較演算子を使用するよりもオブジェクトに問い合わせる方が「オブジェクト指向」です。どちらも読みにくいので、より多くの製品を出荷するのに役立つ方を使用してください。
juanpaco 2013年

どのステートメントを参照していますか?!?他のものへのコメントとして回答を使用しないでください。
Arnaud Meuret 2014

18

defined?(your_var)働くでしょう。何をしているのかに応じて、次のようなこともできますyour_var.nil?


+1はyour_var.nil?、trueまたはfalseを返し、に比べて読み書きに優れてdefined? varいるためです。これをありがとう。
角兵衛2013

28
your_var.nil?エラーになります:undefined local variable or method your_var以前に定義されていない場合
Gobol

16

「if」ではなく「unless」を試す

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
もう1つの便利な方法で質問にうまく答えますね。
見た目

2
ルビースタイルガイドは、「オーバーであれば、負の条件のためのない限り好意」と言うgithub.com/bbatsov/ruby-style-guide
ChrisPhoenix


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?オプションであるためです。
James

8

警告Re:一般的なRubyパターン

これが鍵となる答えです:defined?メソッド。上記の受け入れられた答えはこれを完全に示しています。

しかし、波の下に潜んでいるサメがいます...

この種の一般的なルビパターンを考えてみましょう:

 def method1
    @x ||= method2
 end

 def method2
    nil
 end

method2常に戻りますnil。を初めて呼び出すmethod1とき、@x変数は設定されていないためmethod2、実行されます。そして、method2設定されます@xnil。それは結構です、そしてすべてうまくいきます。しかし、2回目に電話するとmethod1どうなりますか?

@xはすでにnilに設定されていることに注意してください。But method2再び実行されます!! method2がコストのかかる作業である場合、これはあなたが望むものではないかもしれません。

してみましょうdefined?この溶液を用いて、特定のケースが処理されていること- -メソッドが救助に来て、次を使用します。

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

悪魔は詳細にありますが、そのdefined?方法で潜んでいるサメを回避できます。


あなたは完全に正しいです、その特定の警告を強調するためにありがとう
カルガー


5

他の多くの例が示すように、ルビで論理的な選択を行うためにメソッドからブール値を実際に必要としない。実際にブール値が必要でない限り、すべてをブール値に強制するのは不適切な形式です。

ただし、ブール値が絶対に必要な場合。使用する !!(バンバン)または「偽りの偽りは真実を明らかにする」

 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']、文字列として評価される"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ブロックにあると混乱しました。
ポールペッテンギル2015

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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.