Перевірка, чи визначена змінна?


Відповіді:


791

Використовуйте defined?ключове слово ( документація ). Він поверне рядок із типом елемента або nilякщо його не існує.

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

Як коментує skalee: "Варто зазначити, що змінна, яка встановлена ​​на нуль, ініціалізується".

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

92
Варто зазначити, що змінна, для якої встановлено nil , ініціалізується.
skalee

7
Якщо ви хочете встановити змінну, якщо вона не існує, і залишити її в спокої, якщо вона є, дивіться відповідь @ danmayer (за участю ||=оператора) нижче.
jrdioko

2
Ось ще одна дивовижність, на яку я можу ввійти. Якщо ви визначаєте змінну в блоці if, для якої умова ніколи не виконується, defined?все одно повертається true для змінної, визначеної в цьому блоці!
elsurudo

1
Чи є такий метод, defined?що повертає булевий?
stevec

Щоб повернути істина / неправда,!!defined?(object_name)
stevec

91

Це корисно, якщо ви не хочете нічого робити, якщо він існує, але створити його, якщо його немає.

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

Це створює новий екземпляр лише один раз. Після цього він просто продовжує повертати вар.


9
Це дуже ідіоматичний Рубі теж, до речі.
jrdioko

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) вашою змінною. Цей синтаксис поверне справжнє / хибне значення для оцінки в операторі if.


11
Це не обов'язково, оскільки нуль оцінюється як хибне при використанні в тесті
Джеронім

Чому ні defined?(var) == nil?
vol7ron

@ vol7ron - Це абсолютно правильний синтаксис. .nil?Як говорять, використання дзвінка до більш ідіоматичного. Більш "об'єктно-орієнтований" запитувати об'єкт, якщо він, nilніж використовувати оператор порівняння. Читати це не складно, тому використання того, що допоможе вам доставити більше товару.
juanpaco

До якої заяви ви посилаєтесь?!? Не використовуйте відповідь як коментар до чогось іншого.
Арно Меурет

18

defined?(your_var)буду працювати. Залежно від того, що ви робите, ви можете зробити щось подібнеyour_var.nil?


+1, your_var.nil?тому що він повертає істинне помилкове значення і набагато приємніше читати і писати, ніж defined? var. Дякую за це
kakubei

28
your_var.nil?призведе до помилки: undefined local variable or method your_varколи не визначено раніше ...
Gobol

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

ПОПЕРЕДЖЕННЯ Щодо: загального рубінового малюнка

Це ключова відповідь: defined?метод. Прийнята вище відповідь чудово ілюструє це.

Але є акула, яка ховається під хвилями ...

Розглянемо цей тип загального рубінового малюнка:

 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заяву здається надмірно складним
johannes

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 блок буде виконаний

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"

x визначено, хоча він ніколи не призначається!


Це те, що я щойно натрапив. Я очікував 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.