Проверка, если переменная определена?

581

Как я могу проверить, определена ли переменная в Ruby? Есть ли issetспособ -типа в наличии?

Readonly
источник

Ответы:

791

Используйте defined?ключевое слово ( документация ). Он вернет строку с типом элемента или, nilесли он не существует.

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

Как отметил Скали: «Стоит отметить, что переменная, для которой установлено значение nil, инициализирована».

>> n = nil  
>> defined? n
 => "local-variable"
Рикардо Акрас
источник
92
Стоит отметить , что переменная , которая устанавливается в nil это инициализирован.
Скали
7
Если вы хотите установить переменную, если она не существует, и оставить ее в покое, если она есть, см. Ответ @ danmayer (с ||=оператором) ниже.
Джридиоко
2
Вот еще одна странность, с которой я могу столкнуться. Если вы определяете переменную в блоке if, для которого условие никогда не выполняется, она defined?все равно возвращает true для переменной, определенной в этом блоке!
elsurudo
1
Есть ли такой метод defined?возвращает логическое значение?
Stevec
Чтобы вернуть истину / ложь,!!defined?(object_name)
Stevec
91

Это полезно, если вы хотите ничего не делать, если он существует, но создавать его, если он не существует.

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

Это создает новый экземпляр только один раз. После этого он просто продолжает возвращать var.

danmayer
источник
9
Кстати, это очень идиоматичный Ruby и очень типичный.
Джридиоко
38
Только не используйте ||=с булевыми значениями, чтобы не чувствовать боль путаницы.
Эндрю Маршалл
6
Наряду с тем, что сказал @AndrewMarshall, избегайте этой идиомы с чем-нибудь, что также может возвращаться, nilесли вы действительно не хотите вычислять выражение каждый раз, когда оно вызывается, когда оно действительно возвращаетсяnil
nzifnab
1
Если будут работать с Булевыми, и чтобы значение по умолчанию , чтобы быть правдой , если переменная не установлено явно в ЛОЖЬ, вы можете использовать эту конструкцию: 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) с вашей переменной. Этот синтаксис вернет значение true / false для оценки в операторе if.

foomip
источник
11
Это не обязательно, поскольку nil оценивается как false при использовании в тесте
Джером,
Почему нет defined?(var) == nil?
vol7ron
@ vol7ron - это совершенно правильный синтаксис. .nil?Как говорится, использование вызова более идиоматично. Более «объектно-ориентировано» спрашивать объект, если он, nilчем использовать оператор сравнения. Ни то, ни другое не трудно прочитать, поэтому используйте тот, который поможет вам доставить больше продукта.
Хуанпако
На какое заявление вы ссылаетесь?!? Не используйте ответ как комментарий к чему-то другому.
Арно Море
18

defined?(your_var)будет работать. В зависимости от того, что вы делаете, вы также можете сделать что-то вродеyour_var.nil?

digitalsanctum
источник
+1, your_var.nil?потому что он возвращает true из false и гораздо приятнее читать и писать, чем defined? var. Спасибо за это.
Какубей
28
your_var.nil?приведет к ошибке: undefined local variable or method your_varесли не определено ранее ...
Гобол
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
user761856
источник
Что добавляет этот ответ, чего не сказали другие ответы?
Эндрю Гримм
2
Это очень хорошо отвечает на вопрос еще одним полезным способом, не так ли?
смотрите
2
Гид по рубиновому стилю гласит: «Пользуйся, если не закончится, если для негативных условий» github.com/bbatsov/ruby-style-guide
ChrisPhoenix
9

Используйте defined? YourVariable
Keep it simple глупо ..;)

Сакиб Р.
источник
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

Понятно, что код раскраски не нужен, просто приятная наглядность в этом игрушечном примере.

Сардатрион - против злоупотребления SE
источник
Предположительно, потому что nil?это необязательно.
Джеймс
8

ПРЕДУПРЕЖДЕНИЕ Re: Общий шаблон Ruby

Это ключевой ответ: defined?метод. Принятый ответ выше иллюстрирует это отлично.

Но под волнами скрывается акула ...

Рассмотрим этот тип общего шаблона ruby:

 def method1
    @x ||= method2
 end

 def method2
    nil
 end

method2всегда возвращается nil. Первый раз , когда вы звоните method1, то @xпеременная не установлена - поэтому method2будет работать. и method2будет установлен @xв nil. Это хорошо, и все хорошо. Но что происходит во второй раз, когда вы звоните method1?

Помните, что @x уже был установлен в ноль. But method2все еще будет работать снова !! Если method2 является дорогостоящим мероприятием, это может быть не то, что вы хотите.

Пусть defined?метод придет на помощь - с этим решением, этот конкретный случай обрабатывается - используйте следующее:

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

Дьявол кроется в деталях: но вы можете избежать этой скрывающейся акулы с помощью defined?метода.

BKSpurgeon
источник
Вы совершенно правы, спасибо за то, что подчеркнули эту конкретную оговорку
Кулгар
5

Ты можешь попробовать:

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

Потому что это возвращает логическое значение.

Бруно Баррос
источник
SyntaxError: compile error (irb):2: syntax error, unexpected $end, expecting kEND
Эндрю Гримм
использовать unlessутверждение кажется слишком сложным
Иоганнес
5

Как показывают многие другие примеры, на самом деле вам не нужно логическое значение из метода для логического выбора в ruby. Было бы плохой формой привести все к логическому значению, если вам не нужен логический тип.

Но если вам абсолютно необходимо логическое значение. Используйте! (bang bang) или «ложная ложь раскрывает правду».

 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
donnoman
источник
3

Следует отметить, что использование definedдля проверки, задано ли определенное поле в хэше, может вести себя неожиданно:

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

Синтаксис здесь правильный, но defined? var['unknown']будет оцениваться как строка "method", поэтомуif блок будет выполнен

edit: правильная запись для проверки, существует ли ключ в хэше:

if var.key?('unknown')
leberknecht
источник
2

Обратите внимание на различие между «определен» и «назначен».

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

х определяется, хотя он никогда не назначается!

Роберт Клемм
источник
Это то, с чем я только что столкнулся. Я ожидал NameError Exception: undefined local variable or method, и был смущен, когда единственное назначение / упоминание переменной было в блоке if, который не попадал в цель.
Пол Петтенгилл
0

Кроме того, вы можете проверить, определено ли оно в строке в результате интерполяции, если вы кодируете:

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

Система сообщит вам тип, если он определен. Если он не определен, он просто выдаст предупреждение о том, что переменная не инициализирована.

Надеюсь это поможет! :)

Elliott
источник
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
Джон Доннер
источник