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


581

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

Ответы:


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.


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.


11
Это не обязательно, поскольку nil оценивается как false при использовании в тесте
— Джером,

Почему нет defined?(var) == nil?
— vol7ron

@ vol7ron - это совершенно правильный синтаксис. .nil?Как говорится, использование вызова более идиоматично. Более «объектно-ориентировано» спрашивать объект, если он, nilчем использовать оператор сравнения. Ни то, ни другое не трудно прочитать, поэтому используйте тот, который поможет вам доставить больше продукта.
— Хуанпако

На какое заявление вы ссылаетесь?!? Не используйте ответ как комментарий к чему-то другому.
— Арно Море

18

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


+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

Что добавляет этот ответ, чего не сказали другие ответы?
— Эндрю Гримм

2
Это очень хорошо отвечает на вопрос еще одним полезным способом, не так ли?
— смотрите

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?это необязательно.
— Джеймс

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?метода.


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

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

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

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)}"

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

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


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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.